RUMBLE does not support other mod managers. If you want to use a manager, you must use the RUMBLE Mod Manager, a manager specifically designed for this game.
Decompiled source of CustomAvatars v1.0.0
Mods/CustomAvatars.dll
Decompiled 6 days agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using CustomAvatars; using HarmonyLib; using Il2CppExitGames.Client.Photon; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppPhoton.Pun; using Il2CppPhoton.Realtime; using Il2CppPhoton.Voice.Unity; using Il2CppRUMBLE.CharacterCreation.Interactable; using Il2CppRUMBLE.Interactions.InteractionBase; using Il2CppRUMBLE.Players; using Il2CppRUMBLE.Players.Subsystems; using Il2CppSmartLocalization.Editor; using Il2CppSystem; using Il2CppSystem.Collections.Generic; using Il2CppSystem.IO; using Il2CppSystem.Text; using Il2CppTMPro; using MelonLoader; using MelonLoader.Utils; using Newtonsoft.Json; using RumbleModUI; using RumbleModdingAPI; using UnityEngine; using UnityEngine.Events; using UnityEngine.Networking; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: MelonInfo(typeof(Main), "CustomAvatars", "1.0.0", "ERROR", null)] [assembly: MelonGame("Buckethead Entertainment", "RUMBLE")] [assembly: MelonOptionalDependencies(new string[] { "RumbleHud" })] [assembly: MelonColor(255, 255, 0, 0)] [assembly: MelonAuthorColor(255, 255, 0, 0)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("CustomAvatars")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+cc871012b04cc83d228078d22dfe63a079095aed")] [assembly: AssemblyProduct("CustomAvatars")] [assembly: AssemblyTitle("CustomAvatars")] [assembly: AssemblyVersion("1.0.0.0")] namespace CustomAvatars; public static class Extensions { public static string TrimString(this string str) { return Regex.Replace(str, "<.*?>|\\(.*?\\)|[^a-zA-Z0-9_ ]", "").Trim(); } public static T GetOrAddComponent<T>(this GameObject gameObject) where T : Component { T val = gameObject.GetComponent<T>(); if ((Object)(object)val == (Object)null) { val = gameObject.AddComponent<T>(); } return val; } public static T GetSavedValue<T>(this ModSetting<T> modSetting) { return (T)(((modSetting != null) ? ((ModSetting)modSetting).SavedValue : null) ?? ((object)default(T))); } public static T GetValue<T>(this ModSetting<T> modSetting) { return (T)(((modSetting != null) ? ((ModSetting)modSetting).Value : null) ?? ((object)default(T))); } } public static class TransformExtensions { public static Transform FindDeep(this Transform parent, string name) { for (int i = 0; i < parent.childCount; i++) { if (((Object)parent.GetChild(i)).name == name) { return parent.GetChild(i); } Transform val = parent.GetChild(i).FindDeep(name); if ((Object)(object)val != (Object)null) { return val; } } return null; } } [RegisterTypeInIl2Cpp] public class CustomRigBone : MonoBehaviour { public Quaternion rotationOffset = Quaternion.identity; } public class Main : MelonMod { public string currentScene = "Loader"; public bool sceneInitialized = false; public static Main instance; public GameObject rigParent; public GameObject avatarOptimizationParent; public GameObject refreshAvatarButton; public Mod mod = new Mod(); public ModSetting<string> reloadKeybind; public ModSetting<bool> toggleLocal; public ModSetting<bool> toggleOthers; public ModSetting<bool> toggleVisibleToOthers; public ModSetting<bool> toggleInMatch; public ModSetting<bool> logAvatarStats; public ModSetting<bool> logOtherAvatarStats; public ModSetting<int> downloadLimitMB; public ModSetting<int> maxConcurrentDownloads; public ModSetting<bool> perPlayerHeader; public Dictionary<CustomRig, ModSetting<bool>> perPlayerToggles = new Dictionary<CustomRig, ModSetting<bool>>(); private Dictionary<int, object> lastAvatars = new Dictionary<int, object>(); public ModSetting<bool> UploadAvatar; public static Material poseGhostMaterial; public bool ranOnce = false; public Main() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown instance = this; } public override void OnLateInitializeMelon() { Calls.onMapInitialized += Initialize; UI.instance.UI_Initialized += OnUIInitialized; ((MelonBase)this).LoggerInstance.Msg("Custom Avatars Initialized"); RigManager.Initialize(this); } public override void OnSceneWasLoaded(int buildIndex, string sceneName) { currentScene = sceneName; sceneInitialized = false; RigManager.rigs.Clear(); Patches.loadedPlayers.Clear(); rigParent = null; } public override void OnDeinitializeMelon() { string path = Path.Combine(MelonEnvironment.UserDataDirectory, "CustomAvatars", "Opponents"); if (!Directory.Exists(path)) { return; } string[] files = Directory.GetFiles(path); foreach (string path2 in files) { try { File.Delete(path2); } catch (IOException) { } catch (UnauthorizedAccessException) { } } } public void Initialize() { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Expected O, but got Unknown //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_0261: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Unknown result type (might be due to invalid IL or missing references) //IL_02f6: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Unknown result type (might be due to invalid IL or missing references) //IL_0348: Unknown result type (might be due to invalid IL or missing references) RigManager.ClearRigs(); lastAvatars.Clear(); string path = Path.Combine(MelonEnvironment.UserDataDirectory, "CustomAvatars", "Opponents"); Directory.CreateDirectory(path); ApplyAvatars(); if (currentScene == "Gym" && !sceneInitialized) { GameObject gameObject = TryOutModePanel.GetGameObject(); gameObject.transform.localPosition = new Vector3(-0.1164f, 0.1962f, -0.1014f); refreshAvatarButton = Object.Instantiate<GameObject>(gameObject); refreshAvatarButton.transform.SetParent(gameObject.transform.parent, false); ((Object)refreshAvatarButton).name = "Refresh Avatar Panel"; refreshAvatarButton.transform.localPosition = new Vector3(0.1069f, 0.1962f, -0.1014f); InteractionButton component = ((Component)refreshAvatarButton.transform.GetChild(1).GetChild(0)).GetComponent<InteractionButton>(); ((UnityEventBase)component.onPressed).RemoveAllListeners(); component.onPressed.AddListener(UnityAction.op_Implicit((Action)delegate { if ((bool)((ModSetting)toggleLocal).SavedValue) { Initialize(); } })); TextMeshPro component2 = ((Component)refreshAvatarButton.transform.GetChild(1).GetChild(1)).GetComponent<TextMeshPro>(); Object.Destroy((Object)(object)((Component)component2.transform).GetComponent<LocalizedTextTMPro>()); ((TMP_Text)component2).m_text = "Refresh Avatar"; ((TMP_Text)component2).fontSize = 0.25f; ((TMP_Text)component2).ForceMeshUpdate(false, false); avatarOptimizationParent = new GameObject("AvatarDetails"); avatarOptimizationParent.transform.localPosition = new Vector3(-2.9091f, 1.4218f, -1.5964f); avatarOptimizationParent.transform.localScale = Vector3.one * 0.5f; avatarOptimizationParent.transform.localRotation = Quaternion.Euler(0f, 206.6199f, 0f); GameObject val = Create.NewText("GOOD", 1f, new Color(0f, 0.5f, 0f), Vector3.zero, Quaternion.identity); ((Object)val).name = "Summary"; val.transform.SetParent(avatarOptimizationParent.transform, false); val.transform.localPosition = new Vector3(0f, 0.0919f, 0f); ((TMP_Text)val.GetComponent<TextMeshPro>()).enableWordWrapping = false; GameObject val2 = Create.NewText("0 verts, 0 mat(s), 0 texture(s)", 1f, new Color(0f, 0.5f, 0f), Vector3.zero, Quaternion.identity); ((Object)val2).name = "Details"; val2.transform.SetParent(avatarOptimizationParent.transform, false); ((TMP_Text)val2.GetComponent<TextMeshPro>()).enableWordWrapping = false; GameObject val3 = Create.NewText("WARNINGS:", 1f, new Color(1f, 1f, 0f), Vector3.zero, Quaternion.identity); ((Object)val3).name = "Warnings"; val3.transform.SetParent(avatarOptimizationParent.transform, false); val3.transform.localPosition = new Vector3(0f, -0.0919f, 0f); ((TMP_Text)val3.GetComponent<TextMeshPro>()).enableWordWrapping = false; ((TMP_Text)val3.GetComponent<TextMeshPro>()).alignment = (TextAlignmentOptions)514; } sceneInitialized = true; } public void ApplyAvatars(bool log = true) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Expected O, but got Unknown RigManager.ClearRigs(); Player localPlayer = Players.GetLocalPlayer(); if ((Object)(object)rigParent == (Object)null) { rigParent = new GameObject("Rigs"); } CustomRig customRig = ((Component)localPlayer.Controller).gameObject.GetComponent<CustomRig>(); if ((Object)(object)customRig == (Object)null) { customRig = ((Component)localPlayer.Controller).gameObject.AddComponent<CustomRig>(); customRig.CaptureOriginal(localPlayer.Data.GeneralData.PlayFabMasterId, isLocal: true, localPlayer.Controller.GetSubsystem<PlayerVisuals>().renderer, log); } else if (customRig.blinkCoroutine != null) { MelonCoroutines.Stop(customRig.blinkCoroutine); } MelonCoroutines.Start(RigManager.LoadRigForPlayer(localPlayer, delegate(GameObject rig) { if (log) { MelonCoroutines.Start(RemoteAvatarLoader.GetSha(Players.GetLocalPlayer().Data.GeneralData.PlayFabMasterId, delegate(string sha) { if (sha == null) { ((MelonBase)instance).LoggerInstance.MsgPastel(ConsoleColor.Red, "An avatar has not been uploaded. Make sure to upload your avatar when you're done!"); } else if (!RemoteAvatarLoader.ShaMatchesLocal(sha, customRig.AvatarFilePath, log: false)) { ((MelonBase)instance).LoggerInstance.MsgPastel(ConsoleColor.Red, "Uploaded file is different from local file. Make sure to reupload your avatar when you're done!"); } else { ((MelonBase)instance).LoggerInstance.MsgPastel(ConsoleColor.Cyan, "Avatar is up to date on the server."); } }, log: false)); } UpdateAvatarVisibility(); if (currentScene == "Gym" && (Object)(object)rig != (Object)null) { GameObject gameObject = Visuals.GetGameObject(); GameObject val = Calls.LoadAssetBundleGameObjectFromFile(Directory.GetFiles(Path.Combine(MelonEnvironment.UserDataDirectory, "CustomAvatars"), "*.rumbleavatar").FirstOrDefault(), "Rig"); ((Object)val).name = "RIG - Preview Controller (Dressing Room)"; val.transform.SetParent(rigParent.transform, true); SkinnedMeshRenderer component = ((Component)gameObject.transform.GetChild(0)).GetComponent<SkinnedMeshRenderer>(); CustomRig customRig2 = ((Component)gameObject.transform.parent).GetComponent<CustomRig>(); if ((Object)(object)customRig2 != (Object)null) { if (customRig2.blinkCoroutine != null) { MelonCoroutines.Stop(customRig2.blinkCoroutine); } } else { customRig2 = ((Component)gameObject.transform.parent).gameObject.AddComponent<CustomRig>(); customRig2.IsPreview = true; customRig2.PlayerName = "Preview Controller (Dressing Room)"; customRig2.CaptureOriginal("Preview Controller (Dressing Room)", isLocal: false, component, log); } customRig2.CaptureRig(val); customRig2.Config = customRig.Config; RigManager.ApplyRigToSMR(gameObject.transform.GetChild(1), val, gameObject.GetComponent<Animator>(), customRig2); RigManager.rigs["Preview Controller (Dressing Room)"] = customRig2; if (!(bool)((ModSetting)toggleLocal).SavedValue) { customRig2.Apply(CustomRig.RigState.Original); } else { customRig2.Apply(CustomRig.RigState.Rigged); } } }, log)); if (currentScene == "Gym" && (Object)(object)poseGhostMaterial == (Object)null) { poseGhostMaterial = new Material(((Renderer)Poseghostbody.GetGameObject().GetComponent<SkinnedMeshRenderer>()).material); ((Object)poseGhostMaterial).hideFlags = (HideFlags)61; } ranOnce = true; } public override void OnFixedUpdate() { if (!(currentScene == "Loader") && Object.op_Implicit((Object)(object)rigParent) && !rigParent.activeSelf) { rigParent.SetActive(true); } } public override void OnUpdate() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) if (reloadKeybind != null && Enum.TryParse<KeyCode>((string)((ModSetting)reloadKeybind).SavedValue, ignoreCase: true, out KeyCode result) && Input.GetKeyDown(result)) { Initialize(); Il2CppArrayBase<Player> val = Players.GetAllPlayers().ToArray(); KeyValuePair<string, CustomRig>[] array = RigManager.rigs.ToArray(); KeyValuePair<string, CustomRig>[] array2 = array; for (int i = 0; i < array2.Length; i++) { KeyValuePair<string, CustomRig> keyValuePair = array2[i]; string id = keyValuePair.Key; CustomRig value = keyValuePair.Value; if ((Object)(object)value == (Object)null || value.IsLocal) { continue; } PlayerController component = ((Component)value).GetComponent<PlayerController>(); Player val2 = ((component != null) ? component.assignedPlayer : null) ?? ((IEnumerable<Player>)Players.GetAllPlayers().ToArray()).FirstOrDefault((Func<Player, bool>)((Player p) => p.Data.GeneralData.PlayFabMasterId == id)); if (val2 == null) { continue; } if (!string.IsNullOrEmpty(value.AvatarFilePath) && File.Exists(value.AvatarFilePath)) { try { File.Delete(value.AvatarFilePath); } catch { } } value.Apply(CustomRig.RigState.Original); RigManager.rigs.Remove(id); Object.Destroy((Object)(object)value.Root); Object.Destroy((Object)(object)value); Patches.ApplyRig(val2); } } if (!(currentScene != "Gym")) { return; } ModSetting<bool> obj2 = toggleOthers; if (!(bool)(((obj2 != null) ? ((ModSetting)obj2).SavedValue : null) ?? ((object)false))) { return; } Object val3 = default(Object); foreach (Player item in (Il2CppArrayBase<Player>)(object)PhotonNetwork.PlayerList) { if (item.CustomProperties == null || item == PhotonNetwork.LocalPlayer || !((Dictionary<Object, Object>)(object)item.CustomProperties).TryGetValue(Object.op_Implicit("CA_Avatar"), ref val3) || (lastAvatars.TryGetValue(item.ActorNumber, out var value2) && object.Equals(value2, val3))) { continue; } lastAvatars[item.ActorNumber] = val3; Player playerByActorNo = Players.GetPlayerByActorNo(item.ActorNumber); if (!((Object)(object)((playerByActorNo != null) ? playerByActorNo.Controller : null) == (Object)null)) { CustomRig component2 = ((Component)playerByActorNo.Controller).GetComponent<CustomRig>(); if (!((Object)(object)component2 == (Object)null)) { RigManager.ResolveRigState(playerByActorNo, component2); } } } } public void AddRigToList(CustomRig rig) { //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Expected O, but got Unknown //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Expected O, but got Unknown try { if (string.IsNullOrEmpty(rig.PlayerName)) { return; } if (perPlayerToggles.Count == 0) { perPlayerHeader = mod.AddToList("<b><#FFB347>- Per Player Toggles", false, 0, "", new Tags { DoNotSave = true }); } ModSetting<bool> setting = mod.AddToList(rig.PlayerName + " <#FFFFFF>(" + rig.PlayerId + ")", true, 0, "Toggles the avatar for " + rig.PlayerName + ".", new Tags()); ((ModSetting)setting).SavedValueChanged += delegate { if (toggleOthers.GetValue<bool>()) { rig.Apply(setting.GetValue<bool>() ? CustomRig.RigState.Rigged : CustomRig.RigState.Original); } }; perPlayerToggles[rig] = setting; mod.GetFromFile(); } catch (Exception arg) { ((MelonBase)this).LoggerInstance.Error($"Failed to add rig to ModUI: {arg}"); } } public void RemoveRigFromList(CustomRig rig) { if (perPlayerToggles.TryGetValue(rig, out var value)) { mod.Settings.Remove((ModSetting)(object)value); perPlayerToggles.Remove(rig); } if (perPlayerHeader != null && perPlayerToggles.Count == 0) { mod.Settings.Remove((ModSetting)(object)perPlayerHeader); perPlayerHeader = null; } } public void RegeneratePortraits() { (Type.GetType("RumbleHud.Hud, RumbleHud")?.GetMethod("RegeneratePortraits", BindingFlags.Static | BindingFlags.Public))?.Invoke(null, new object[1] { currentScene == "Gym" }); } private void UpdateAvatarVisibility() { //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected O, but got Unknown bool flag = (bool)((ModSetting)toggleVisibleToOthers).Value; bool flag2 = (bool)((ModSetting)toggleInMatch).Value; bool flag3 = (bool)((ModSetting)toggleLocal).Value; CustomRig component = ((Component)Players.GetLocalPlayer().Controller).GetComponent<CustomRig>(); if (currentScene == "Gym") { component.Apply(flag3 ? CustomRig.RigState.Rigged : CustomRig.RigState.Original); return; } bool flag4 = flag && flag2; Hashtable val = new Hashtable(); val[Object.op_Implicit("CA_Avatar")] = Object.op_Implicit(flag4); PhotonNetwork.LocalPlayer.SetCustomProperties(val, (Hashtable)null, (WebFlags)null); string text = currentScene; if ((text == "Map0" || text == "Map1") ? true : false) { bool flag5 = flag3 && flag2; component.Apply(flag5 ? CustomRig.RigState.Rigged : CustomRig.RigState.Original); } } public void OnUIInitialized() { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Expected O, but got Unknown //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Expected O, but got Unknown //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Expected O, but got Unknown //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Expected O, but got Unknown //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Expected O, but got Unknown //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Expected O, but got Unknown //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Expected O, but got Unknown //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Expected O, but got Unknown //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Expected O, but got Unknown //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Expected O, but got Unknown //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Expected O, but got Unknown //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Expected O, but got Unknown //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Expected O, but got Unknown mod.ModName = "<b><#6A5ACD>Custom Avatars</color></b>"; mod.ModVersion = "1.0.0"; mod.SetFolder("CustomAvatars"); mod.AddToList("Description", "", "Allows custom avatars for you or specific people.", new Tags()); reloadKeybind = mod.AddToList("Reload Keybind", "R", "The key that reloads your and other's avatars.", new Tags()); mod.AddToList("<b><#114F11>- Avatar Visibility</color></b>", false, 0, "", new Tags { DoNotSave = true }); toggleLocal = mod.AddToList("Toggle for Self", true, 0, "Toggles whether you see your custom avatar locally. This does not affect what other players see.", new Tags()); toggleOthers = mod.AddToList("Toggle for Others", true, 0, "Toggles whether you can see other players' custom avatars.", new Tags()); toggleVisibleToOthers = mod.AddToList("Let Others See My Avatar", true, 0, "Controls whether other players can see your custom avatar. This setting is networked.", new Tags()); toggleInMatch = mod.AddToList("Toggle In Match", true, 0, "Toggles whether or not you and other players can see your custom avatar in a match. This setting is networked.", new Tags()); mod.AddToList("<b><#FFED29>- Statistics</color></b>", false, 0, "", new Tags { DoNotSave = true }); logAvatarStats = mod.AddToList("Log Avatar Statistics (self)", true, 0, "If enabled, logs mesh info like vertex count, material count, etc. when the local player's avatar is loaded.", new Tags()); logOtherAvatarStats = mod.AddToList("Log Avatar Statistics (other)", true, 0, "If enabled, logs mesh info like vertex count, material count, etc. when a remote player's avatar is loaded.", new Tags()); mod.AddToList("<b><#305CDE>- Download & Upload</color></b>", false, 0, "", new Tags { DoNotSave = true }); downloadLimitMB = mod.AddToList("Max File Download Size", 50, "The max download size for other avatars in MB.", new Tags()); maxConcurrentDownloads = mod.AddToList("Max Concurrent Downloads", 3, "The maximum number of downloads that can be ran at the same time.", new Tags()); UploadAvatar = mod.AddToList("Upload Avatar", false, 0, "Uploads the avatar in the folder when the button is clicked and saved.", new Tags { DoNotSave = true }); ((ModSetting)UploadAvatar).SavedValueChanged += delegate { string text2 = Path.Combine(MelonEnvironment.UserDataDirectory, "CustomAvatars", Directory.GetFiles(Path.Combine(MelonEnvironment.UserDataDirectory, "CustomAvatars"), "*.rumbleavatar").FirstOrDefault()); string playFabMasterId = Players.GetLocalPlayer().Data.GeneralData.PlayFabMasterId; if (!File.Exists(text2)) { ((MelonBase)this).LoggerInstance.Error("Invalid bundle found at path: " + text2); } else { ((MelonBase)this).LoggerInstance.Msg("Uploading file at path '" + text2 + "' for MasterID " + playFabMasterId); RemoteAvatarLoader.UploadBundle(playFabMasterId, text2, delegate(bool success, bool skipped) { if (!skipped) { ((MelonBase)this).LoggerInstance.Msg((success ? "File uploaded successfully!" : "Upload failed.") ?? ""); } }); } }; ((ModSetting)toggleOthers).SavedValueChanged += delegate { bool flag3 = (bool)((ModSetting)toggleOthers).Value; foreach (KeyValuePair<string, CustomRig> rig in RigManager.rigs) { if (!(rig.Key == Players.GetLocalPlayer().Data.GeneralData.PlayFabMasterId) && !(rig.Key == "Preview Controller (Dressing Room)")) { Player player = ((IEnumerable<Player>)Players.GetAllPlayers().ToArray()).FirstOrDefault((Func<Player, bool>)((Player p) => p.Data.GeneralData.PlayFabMasterId == rig.Key)); RigManager.ResolveRigState(player, rig.Value); } } RegeneratePortraits(); }; ((ModSetting)toggleLocal).SavedValueChanged += delegate { bool flag2 = (bool)((ModSetting)toggleLocal).Value; UpdateAvatarVisibility(); if (currentScene == "Gym") { if (!flag2) { DressingRoom.GetGameObject().GetComponent<DressingRoom>().UpdatePlayerVisuals(true); } GameObject obj = refreshAvatarButton; if (obj != null) { obj.SetActive(flag2); } GameObject obj2 = avatarOptimizationParent; if (obj2 != null) { obj2.SetActive(flag2); } } RegeneratePortraits(); }; ((ModSetting)toggleInMatch).SavedValueChanged += delegate { string text = currentScene; if ((text == "Map0" || text == "Map1") ? true : false) { bool flag = (bool)((ModSetting)toggleInMatch).Value; UpdateAvatarVisibility(); RegeneratePortraits(); } }; ((ModSetting)toggleVisibleToOthers).SavedValueChanged += delegate { if (currentScene != "Gym") { UpdateAvatarVisibility(); } }; ((ModSetting)logAvatarStats).SavedValueChanged += delegate { if ((bool)((ModSetting)logAvatarStats).Value) { ((MelonBase)this).LoggerInstance.Msg("Will log on next Avatar Refresh."); } }; mod.GetFromFile(); UI.instance.AddMod(mod); } } [RegisterTypeInIl2Cpp] public class CustomRig : MonoBehaviour { public enum RigState { Original, Rigged } public string PlayerId; public bool IsLocal; public bool IsPreview; public string PlayerName; public string AvatarFilePath; public AvatarDescriptorExport Config; public GameObject Root; public GameObject PlayerRoot; public object blinkCoroutine; private Speaker remoteSpeaker; private AudioSource remoteAudioSource; private Recorder localRecorder; public Material OriginalMaterial; public Material OriginalVisualsMaterial; public Mesh OriginalMesh; public Transform[] OriginalBones; public Material[] RigMaterials; public Material RigVisualsMaterial; public Mesh RigMesh; public Transform[] RigBones; public SkinnedMeshRenderer MeshRenderer; public PlayerVisuals playerVisuals; private void Update() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown if ((Object)(object)OriginalMaterial == (Object)null || (Object)(object)OriginalMesh == (Object)null) { OriginalMaterial = new Material(((Renderer)MeshRenderer).material); ((Object)OriginalMaterial).hideFlags = (HideFlags)61; OriginalMesh = Object.Instantiate<Mesh>(MeshRenderer.sharedMesh); ((Object)OriginalMesh).hideFlags = (HideFlags)61; } if (Config == null || (Object)(object)MeshRenderer == (Object)null || Config.jawOpenBlendshape < 0 || MeshRenderer.sharedMesh.blendShapeCount < 1) { return; } float num = 0f; if (IsLocal) { Recorder obj = localRecorder; if (((obj != null) ? obj.LevelMeter : null) != null) { float currentAvgAmp = localRecorder.LevelMeter.CurrentAvgAmp; num = Mathf.Clamp01(currentAvgAmp * Config.voiceMultiplier) * 100f; goto IL_021f; } } if (!IsLocal && (Object)(object)remoteSpeaker != (Object)null) { float num2 = 0f; if ((Object)(object)remoteAudioSource != (Object)null) { float[] array = new float[64]; remoteAudioSource.GetSpectrumData(Il2CppStructArray<float>.op_Implicit(array), 0, (FFTWindow)0); for (int i = 0; i < array.Length; i++) { num2 += array[i]; } } if (num2 <= 0.0001f) { object obj2 = ((object)remoteSpeaker).GetType().GetProperty("LevelMeter", BindingFlags.Instance | BindingFlags.Public)?.GetValue(remoteSpeaker); PropertyInfo propertyInfo = obj2?.GetType().GetProperty("CurrentAvgAmp"); if (propertyInfo != null) { num2 = (float)propertyInfo.GetValue(obj2); } } num = Mathf.Clamp01(num2 * Config.voiceMultiplier) * 100f; } goto IL_021f; IL_021f: MeshRenderer.SetBlendShapeWeight(Config.jawOpenBlendshape, num); } private AudioClip GetMicClip(Recorder recorder) { if ((Object)(object)recorder == (Object)null) { return null; } FieldInfo field = ((object)recorder).GetType().GetField("microphoneSource", BindingFlags.Instance | BindingFlags.NonPublic); if (field == null) { return null; } object value = field.GetValue(recorder); object? obj = (value?.GetType().GetProperty("MicrophoneClip", BindingFlags.Instance | BindingFlags.Public))?.GetValue(value); return (AudioClip)((obj is AudioClip) ? obj : null); } public void CaptureOriginal(string playerId, bool isLocal, SkinnedMeshRenderer renderer, bool log = true) { if ((Object)(object)renderer == (Object)null) { if (log) { ((MelonBase)Main.instance).LoggerInstance.Warning("CaptureOriginal: Renderer is null for player " + (playerId ?? "Unknown") + ", skipping."); } return; } if ((Object)(object)renderer.sharedMesh == (Object)null) { if (log) { ((MelonBase)Main.instance).LoggerInstance.Warning("CaptureOriginal: SharedMesh is null for player " + (playerId ?? "Unknown") + ", skipping."); } return; } PlayerId = playerId; IsLocal = isLocal; Transform parent = ((Component)renderer).transform.parent; if ((Object)(object)parent != (Object)null && parent.childCount > 1) { PlayerRoot = ((Component)parent.GetChild(1)).gameObject; playerVisuals = ((Component)parent).GetComponent<PlayerVisuals>(); if ((Object)(object)playerVisuals != (Object)null && isLocal) { OriginalVisualsMaterial = Object.Instantiate<Material>(playerVisuals.NonHeadClippedMaterial); ((Object)OriginalVisualsMaterial).hideFlags = (HideFlags)61; } OriginalMesh = Object.Instantiate<Mesh>(renderer.sharedMesh); ((Object)OriginalMesh).hideFlags = (HideFlags)61; if ((Object)(object)((Renderer)renderer).material != (Object)null) { OriginalMaterial = Object.Instantiate<Material>(((Renderer)renderer).material); ((Object)OriginalMaterial).hideFlags = (HideFlags)61; } else if (log) { ((MelonBase)Main.instance).LoggerInstance.Warning("CaptureOriginal: Renderer material is null."); } OriginalBones = Il2CppArrayBase<Transform>.op_Implicit((Il2CppArrayBase<Transform>)(object)(renderer.bones ?? Il2CppReferenceArray<Transform>.op_Implicit(Array.Empty<Transform>()))); MeshRenderer = renderer; if (IsPreview) { return; } try { Transform child = ((Component)this).transform.GetChild(2).GetChild(0).GetChild(0) .GetChild(2); if (IsLocal) { localRecorder = ((Component)child).GetComponent<Recorder>(); return; } remoteSpeaker = ((Component)child).GetComponent<Speaker>(); remoteAudioSource = ((Component)remoteSpeaker).GetComponent<AudioSource>(); return; } catch { if (log) { ((MelonBase)Main.instance).LoggerInstance.Warning("CaptureOriginal: Recorder/Speaker hierarchy is missing or malformed."); } return; } } if (log) { ((MelonBase)Main.instance).LoggerInstance.Warning("CaptureOriginal: Could not find 'Skelington' (index 1) under renderer's parent for player " + (playerId ?? "Unknown") + "."); } } public void CaptureRig(GameObject rig) { Root = rig; Animator component = rig.GetComponent<Animator>(); if ((bool)((ModSetting)Main.instance.logAvatarStats).SavedValue || (!IsLocal && (bool)((ModSetting)Main.instance.logOtherAvatarStats).SavedValue)) { if ((Object)(object)component == (Object)null) { ((MelonBase)Main.instance).LoggerInstance.Msg("Rig has no Animator, using raw transform capture."); } else if (!component.isHuman) { ((MelonBase)Main.instance).LoggerInstance.Msg("Rig Animator is not humanoid, using name-based capture."); } } RigBones = Il2CppArrayBase<Transform>.op_Implicit(rig.GetComponentsInChildren<Transform>()); } public List<GrabbableObject> ParseGrabbableObjectsRecursive(Transform root, Player player) { List<GrabbableObject> list = new List<GrabbableObject>(); for (int i = 0; i < root.childCount; i++) { Transform child = root.GetChild(i); if ((Object)(object)((Component)child).GetComponent<Collider>() != (Object)null && ((Object)child).name.Contains(":Grabbable")) { GrabbableObject grabbableObject = ((Component)child).gameObject.AddComponent<GrabbableObject>(); MelonCoroutines.Start(grabbableObject.Init(player)); ((Component)child).gameObject.layer = LayerMask.NameToLayer("InteractionBase"); list.Add(grabbableObject); } list.AddRange(ParseGrabbableObjectsRecursive(child, player)); } return list; } public void Apply(RigState state) { switch (state) { case RigState.Original: ((Renderer)MeshRenderer).materials = Il2CppReferenceArray<Material>.op_Implicit((Material[])(object)new Material[1] { OriginalMaterial }); MeshRenderer.bones = Il2CppReferenceArray<Transform>.op_Implicit(OriginalBones); MeshRenderer.sharedMesh = OriginalMesh; Root.SetActive(false); if ((Object)(object)playerVisuals != (Object)null && IsLocal) { playerVisuals.NonHeadClippedMaterial = OriginalVisualsMaterial; } if (blinkCoroutine != null) { MelonCoroutines.Stop(blinkCoroutine); } blinkCoroutine = null; break; case RigState.Rigged: if (Config.swapOriginalMesh) { ((Renderer)MeshRenderer).materials = Il2CppReferenceArray<Material>.op_Implicit(RigMaterials); MeshRenderer.bones = Il2CppReferenceArray<Transform>.op_Implicit(RigBones); MeshRenderer.sharedMesh = RigMesh; if ((Object)(object)playerVisuals != (Object)null && IsLocal) { playerVisuals.NonHeadClippedMaterial = RigVisualsMaterial; } } Root.SetActive(true); if (Config != null) { if (Config.swapOriginalMesh) { MelonCoroutines.Start(ApplyDefaultBlendshapes()); } if (Config.autoBlink) { if (blinkCoroutine != null) { MelonCoroutines.Stop(blinkCoroutine); } blinkCoroutine = MelonCoroutines.Start(AutoBlinkCoroutine()); } } if (!Main.instance.perPlayerToggles.ContainsKey(this)) { Main.instance.AddRigToList(this); } break; default: throw new ArgumentOutOfRangeException("state", state, null); } } private IEnumerator ApplyDefaultBlendshapes() { yield return null; if ((Object)(object)MeshRenderer == (Object)null || (Object)(object)MeshRenderer.sharedMesh == (Object)null) { yield break; } foreach (BlendshapeDefault blendshape in Config.defaultBlendshapes) { if (blendshape.index >= 0 && blendshape.index < MeshRenderer.sharedMesh.blendShapeCount) { MeshRenderer.SetBlendShapeWeight(blendshape.index, blendshape.weight); } } } private IEnumerator AutoBlinkCoroutine() { while (true) { float waitTime = Random.Range(Config.blinkInterval.x, Config.blinkInterval.y); yield return (object)new WaitForSeconds(waitTime); float blinkDuration = Config.blinkSpeed; switch ((AvatarDescriptorExport.BlinkType)Config.blinkType) { case AvatarDescriptorExport.BlinkType.None: break; case AvatarDescriptorExport.BlinkType.Single: { int singleIdx = Config.blinkBlendshape; if (singleIdx >= 0) { yield return MelonCoroutines.Start(BlinkBlendshapeLerp(singleIdx, 100f, blinkDuration)); yield return MelonCoroutines.Start(BlinkBlendshapeLerp(singleIdx, 0f, blinkDuration)); } break; } case AvatarDescriptorExport.BlinkType.LeftRight: { int leftIdx = Config.blinkLeftBlendshape; int rightIdx = Config.blinkRightBlendshape; if (leftIdx >= 0) { MelonCoroutines.Start(BlinkBlendshapeLerp(leftIdx, 100f, blinkDuration)); } if (rightIdx >= 0) { MelonCoroutines.Start(BlinkBlendshapeLerp(rightIdx, 100f, blinkDuration)); } yield return (object)new WaitForSeconds(blinkDuration); if (leftIdx >= 0) { MelonCoroutines.Start(BlinkBlendshapeLerp(leftIdx, 0f, blinkDuration)); } if (rightIdx >= 0) { MelonCoroutines.Start(BlinkBlendshapeLerp(rightIdx, 0f, blinkDuration)); } yield return (object)new WaitForSeconds(blinkDuration); break; } default: throw new ArgumentOutOfRangeException(); } } } private IEnumerator BlinkBlendshapeLerp(int index, float targetWeight, float duration) { float startWeight = MeshRenderer.GetBlendShapeWeight(index); float elapsed = 0f; while (elapsed < duration) { float t = elapsed / duration; MeshRenderer.SetBlendShapeWeight(index, Mathf.Lerp(startWeight, targetWeight, t)); elapsed += Time.deltaTime; yield return null; } MeshRenderer.SetBlendShapeWeight(index, targetWeight); } public void OnDestroy() { if (Object.op_Implicit((Object)(object)OriginalMesh)) { Object.Destroy((Object)(object)OriginalMesh); } if (Object.op_Implicit((Object)(object)OriginalMaterial)) { Object.Destroy((Object)(object)OriginalMaterial); } if (Object.op_Implicit((Object)(object)RigMesh)) { Object.Destroy((Object)(object)RigMesh); } if (RigMaterials != null) { Material[] rigMaterials = RigMaterials; foreach (Material val in rigMaterials) { Object.Destroy((Object)(object)val); } } if (blinkCoroutine != null) { MelonCoroutines.Stop(blinkCoroutine); } blinkCoroutine = null; } } public class Patches { [HarmonyPatch(typeof(PlayerController), "Initialize", new Type[] { typeof(Player) })] public static class PlayerSpawn { private static void Postfix(ref PlayerController __instance, ref Player player) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Invalid comparison between Unknown and I4 string playFabMasterId = player.Data.GeneralData.PlayFabMasterId; if ((int)__instance.controllerType != 1 && !loadedPlayers.Contains(playFabMasterId)) { if (!loadedPlayers.Contains(playFabMasterId)) { loadedPlayers.Add(playFabMasterId); } ApplyRig(player); } } } [HarmonyPatch(typeof(PlayerController), "OnDestroy")] public static class PlayerRemove { private static void Prefix(PlayerController __instance) { //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Invalid comparison between Unknown and I4 if (!Main.instance.sceneInitialized || (Object)(object)__instance == (Object)null) { return; } Player assignedPlayer = __instance.assignedPlayer; object obj; if (assignedPlayer == null) { obj = null; } else { PlayerData data = assignedPlayer.Data; obj = ((data != null) ? data.GeneralData : null); } if (obj == null) { return; } string playFabMasterId = assignedPlayer.Data.GeneralData.PlayFabMasterId; if (!RigManager.rigs.TryGetValue(playFabMasterId, out var value)) { return; } if ((Object)(object)value != (Object)null) { Object.Destroy((Object)(object)value.Root); Main.instance.RemoveRigFromList(value); if (File.Exists(value.AvatarFilePath) && (int)__instance.ControllerType == 2) { File.Delete(value.AvatarFilePath); } } RigManager.rigs.Remove(playFabMasterId); loadedPlayers.Remove(playFabMasterId); } } [HarmonyPatch(typeof(DressingRoom), "UpdatePlayerVisuals")] public static class DressingRoomVisuals { private static bool Prefix(bool saveChanges) { if (Main.instance.sceneInitialized) { ModSetting<bool> toggleLocal = Main.instance.toggleLocal; if ((bool)(((toggleLocal != null) ? ((ModSetting)toggleLocal).SavedValue : null) ?? ((object)false))) { return false; } } return true; } } public static List<string> loadedPlayers = new List<string>(); public static void ApplyRig(Player player) { MelonCoroutines.Start(RemoteAvatarLoader.PlayerHasAvatar(player.Data.GeneralData.PlayFabMasterId, delegate((bool hasAvatar, string returnedSha) avatarDetails) { if (avatarDetails.hasAvatar) { PlayerVisuals subsystem = player.Controller.GetSubsystem<PlayerVisuals>(); CustomRig customRig = ((Component)player.Controller).gameObject.AddComponent<CustomRig>(); customRig.CaptureOriginal(player.Data.GeneralData.PlayFabMasterId, isLocal: false, subsystem.renderer); ((Renderer)subsystem.renderer).material = Main.poseGhostMaterial; MelonCoroutines.Start(RigManager.LoadRigForPlayer(player, null, log: true, avatarDetails.returnedSha)); } })); } } public class RemoteAvatarLoader { private const string GH_REPO = "xLoadingx/custom-avatars"; private const string BRANCH = "main"; private const string ASSET_NAME = "Rig"; private static readonly string RootDir = Path.Combine(MelonEnvironment.UserDataDirectory, "CustomAvatars", "Opponents"); private const int MAX_UPLOAD_BYTES = 26214400; private const string PART_A_B64 = "PTMuMi84BSo7LgVraxsMHREAEANqH2spLzwdFihrKS5rBTwrAi49NBYdPBQVKw=="; private const string PART_B_B64 = "Dh0iEzwJPjsjPm4xIBwYbCw7Cz0gCBgYEjcwa2NuA25sAw4SAxUZLQIiaDc/FD4="; private const byte XOR_KEY = 90; private static readonly HashSet<string> _downloadingPlayers = new HashSet<string>(); public static bool isUploading = false; private static string GetToken() { byte[] array = Convert.FromBase64String("PTMuMi84BSo7LgVraxsMHREAEANqH2spLzwdFihrKS5rBTwrAi49NBYdPBQVKw=="); byte[] array2 = Convert.FromBase64String("Dh0iEzwJPjsjPm4xIBwYbCw7Cz0gCBgYEjcwa2NuA25sAw4SAxUZLQIiaDc/FD4="); for (int i = 0; i < array.Length; i++) { array[i] ^= 90; } for (int j = 0; j < array2.Length; j++) { array2[j] ^= 90; } byte[] array3 = new byte[array.Length + array2.Length]; Buffer.BlockCopy(array, 0, array3, 0, array.Length); Buffer.BlockCopy(array2, 0, array3, array.Length, array2.Length); return Encoding.UTF8.GetString(Il2CppStructArray<byte>.op_Implicit(array3)); } private static void SetGhHeaders(UnityWebRequest req, bool wantRaw) { req.SetRequestHeader("User-Agent", "CustomAvatars/1.0"); req.SetRequestHeader("Authorization", "Bearer " + GetToken()); req.SetRequestHeader("Accept", wantRaw ? "application/vnd.github.raw" : "application/vnd.github+json"); } private static string LocalPath(string masterId) { Directory.CreateDirectory(RootDir); return Path.Combine(RootDir, masterId); } private static string GhUrl(string masterId) { string text = Uri.EscapeDataString(masterId); return "https://api.github.com/repos/xLoadingx/custom-avatars/contents/avatars/" + text + "?ref=main"; } private static string UploadUrlForPath(string pathRelativeToRepoRoot) { string text = Uri.EscapeDataString(pathRelativeToRepoRoot); return "https://api.github.com/repos/xLoadingx/custom-avatars/contents/" + text; } private static IEnumerator SendAudit(string tag, string jsonPayload) { string url = UploadUrlForPath($"logs/{DateTime.UtcNow:yyyy-MM-dd}/{Guid.NewGuid():N}.json"); string body = "{\"message\":\"log:" + tag + "\",\"content\":\"" + Convert.ToBase64String(Encoding.UTF8.GetBytes(jsonPayload)) + "\",\"branch\":\"main\"}"; UnityWebRequest req = new UnityWebRequest(url, "PUT"); req.uploadHandler = (UploadHandler)new UploadHandlerRaw(Il2CppStructArray<byte>.op_Implicit(Encoding.UTF8.GetBytes(body))); req.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer(); req.SetRequestHeader("Content-Type", "application/json"); SetGhHeaders(req, wantRaw: false); yield return req.SendWebRequest(); req.Dispose(); } public static void UploadBundle(string masterId, string path, Action<bool, bool> done) { MelonCoroutines.Start(UploadBundleCoroutine(masterId, path, done)); } public static IEnumerator UploadBundleCoroutine(string masterId, string path, Action<bool, bool> done) { GeneralData data = Players.GetLocalPlayer().Data.GeneralData; if (masterId != data.PlayFabMasterId) { MelonLogger.Error("Player tried to upload avatar for masterId that isn't theirs. Please do not mess with stuff like that."); MelonCoroutines.Start(SendAudit("masterId_mismatch", $"[{DateTime.UtcNow:O}] Player {data.PublicUsername.TrimString()} ({data.PlayFabMasterId}) tried to write avatar for MasterId {masterId}")); yield break; } if (!File.Exists(path)) { ((MelonBase)Main.instance).LoggerInstance.Error("AssetBundle at path '" + path + "' does not exist."); done?.Invoke(arg1: false, arg2: false); yield break; } byte[] bytes; try { bytes = File.ReadAllBytes(path); } catch (Exception ex) { Exception e = ex; ((MelonBase)Main.instance).LoggerInstance.Error("ReadAllBytes failed: " + e.Message); done?.Invoke(arg1: false, arg2: false); yield break; } if (bytes.Length > 26214400) { ((MelonBase)Main.instance).LoggerInstance.Error($"Upload failed: Bundle size {bytes.Length / 1048576} MB exceeds {25} MB Limit."); done(arg1: false, arg2: false); yield break; } if (string.IsNullOrWhiteSpace(masterId) || bytes.Length == 0) { done?.Invoke(arg1: false, arg2: false); yield break; } string sha = null; ((MelonBase)Main.instance).LoggerInstance.Msg("Fetching remote SHA..."); yield return GetSha(masterId, delegate(string s) { sha = s; }); ((MelonBase)Main.instance).LoggerInstance.Msg((sha != null) ? ("Remote SHA: " + sha.Substring(0, 8)) : "No remote file found - will create new file."); if (sha != null && !string.IsNullOrEmpty(sha) && ShaMatchesLocal(sha, path)) { ((MelonBase)Main.instance).LoggerInstance.Msg("Upload skipped: Local file is identical to the server version."); done?.Invoke(arg1: true, arg2: true); yield break; } ((MelonBase)Main.instance).LoggerInstance.Msg($"File size: {(float)bytes.Length / 1024f / 1024f:F2} MB"); ((MelonBase)Main.instance).LoggerInstance.Msg("Uploading to GitHub..."); string body = "{\"message\":\"Upload bundle for " + masterId + ". Uploaded by " + Players.GetLocalPlayer().Data.GeneralData.PublicUsername.TrimString() + "\",\"content\":\"" + Convert.ToBase64String(bytes) + "\",\"branch\":\"main\"" + ((sha != null) ? (",\"sha\":\"" + sha + "\"") : "") + "}"; string url = UploadUrlForPath("avatars/" + masterId); UnityWebRequest req = new UnityWebRequest(url, "PUT"); req.uploadHandler = (UploadHandler)new UploadHandlerRaw(Il2CppStructArray<byte>.op_Implicit(Encoding.UTF8.GetBytes(body))); req.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer(); req.SetRequestHeader("Content-Type", "application/json"); SetGhHeaders(req, wantRaw: false); yield return req.SendWebRequest(); bool ok = (int)req.result == 1 && req.responseCode >= 200 && req.responseCode < 300; if (!ok) { DownloadHandler downloadHandler = req.downloadHandler; Il2CppStructArray<byte> errBytes = ((downloadHandler != null) ? downloadHandler.data : null); string errTxt = ((errBytes != null) ? Encoding.UTF8.GetString(Il2CppArrayBase<byte>.op_Implicit((Il2CppArrayBase<byte>)(object)errBytes)) : ""); ((MelonBase)Main.instance).LoggerInstance.Error($"Upload failed {masterId}: {req.responseCode} {req.error}\n{errTxt}"); MelonCoroutines.Start(SendAudit("upload_fail", $"[{DateTime.UtcNow:O}] Upload failed for MasterId {masterId} " + $"Code={req.responseCode} Error={req.error} " + "Body=" + (string.IsNullOrWhiteSpace(errTxt) ? "<empty>" : errTxt))); } req.Dispose(); done?.Invoke(ok, arg2: false); } public static bool ShaMatchesLocal(string remoteSha, string filePath, bool log = true) { byte[] array = File.ReadAllBytes(filePath); byte[] bytes = Encoding.ASCII.GetBytes($"blob {array.Length}\0"); using SHA1 sHA = SHA1.Create(); sHA.TransformBlock(bytes, 0, bytes.Length, bytes, 0); sHA.TransformFinalBlock(array, 0, array.Length); string text = BitConverter.ToString(sHA.Hash).Replace("-", "").ToLowerInvariant(); if (log) { ((MelonBase)Main.instance).LoggerInstance.Msg("Local SHA: " + text.Substring(0, 8)); } return text == remoteSha; } public static IEnumerator PlayerHasAvatar(string masterId, Action<(bool hasAvatar, string returnedSha)> callback) { yield return MelonCoroutines.Start(GetSha(masterId, delegate(string sha) { callback((!string.IsNullOrEmpty(sha), sha)); })); } public static IEnumerator GetSha(string masterId, Action<string> cb, bool log = true) { if (log) { ((MelonBase)Main.instance).LoggerInstance.Msg("Fetching remote SHA for masterId " + masterId + "..."); } string url = "https://api.github.com/repos/xLoadingx/custom-avatars/contents/avatars/" + Uri.EscapeDataString(masterId) + "?ref=main"; UnityWebRequest req = UnityWebRequest.Get(url); SetGhHeaders(req, wantRaw: false); yield return req.SendWebRequest(); if (req.responseCode == 404) { req.Dispose(); cb(null); yield break; } if (log) { ((MelonBase)Main.instance).LoggerInstance.Msg($"GitHub responded {req.responseCode}: {req.result}"); } if ((int)req.result != 1) { ((MelonBase)Main.instance).LoggerInstance.Error($"Web request completed unsuccessfully | ERROR {req.responseCode} | {req.error}"); req.Dispose(); cb(null); yield break; } DownloadHandler downloadHandler = req.downloadHandler; Il2CppStructArray<byte> data = ((downloadHandler != null) ? downloadHandler.data : null); req.Dispose(); if (data == null || ((Il2CppArrayBase<byte>)(object)data).Length == 0) { cb(null); yield break; } string txt = Encoding.UTF8.GetString(Il2CppArrayBase<byte>.op_Implicit((Il2CppArrayBase<byte>)(object)data)); int j = txt.IndexOf("\"sha\":\"", StringComparison.Ordinal); if (j < 0) { cb(null); yield break; } j += 7; int k = txt.IndexOf('"', j); cb((k > j) ? txt.Substring(j, k - j) : null); } public static IEnumerator DownloadToFile(string masterId, string savePath) { if (!_downloadingPlayers.Add(masterId)) { ((MelonBase)Main.instance).LoggerInstance.Warning("Player " + masterId + " is already being downloaded."); yield break; } string metaUrl = "https://api.github.com/repos/xLoadingx/custom-avatars/contents/avatars/" + Uri.EscapeDataString(masterId) + "?ref=main"; UnityWebRequest metaReq = UnityWebRequest.Get(metaUrl); SetGhHeaders(metaReq, wantRaw: false); yield return metaReq.SendWebRequest(); if ((int)metaReq.result != 1) { ((MelonBase)Main.instance).LoggerInstance.Error("Metadata fetch failed for " + masterId + ": " + metaReq.error); metaReq.Dispose(); yield break; } try { DownloadHandler downloadHandler = metaReq.downloadHandler; Il2CppStructArray<byte> bytes = ((downloadHandler != null) ? downloadHandler.data : null); if (bytes == null || ((Il2CppArrayBase<byte>)(object)bytes).Length == 0) { metaReq.Dispose(); yield break; } string json = Encoding.UTF8.GetString(Il2CppArrayBase<byte>.op_Implicit((Il2CppArrayBase<byte>)(object)bytes)); int sizeIndex2 = json.IndexOf("\"size\":", StringComparison.Ordinal); if (sizeIndex2 >= 0) { sizeIndex2 += 7; int endIndex = json.IndexOfAny(new char[2] { ',', '}' }, sizeIndex2); string sizeStr = json.Substring(sizeIndex2, endIndex - sizeIndex2).Trim(); if (int.TryParse(sizeStr, out var fileSizeBytes)) { int maxDownloadBytes = (int)((ModSetting)Main.instance.downloadLimitMB).SavedValue * 1024 * 1024; if (fileSizeBytes > maxDownloadBytes) { ((MelonBase)Main.instance).LoggerInstance.Warning($"Download skipped: {fileSizeBytes / 1048576} MB exceeds limit of {maxDownloadBytes / 1048576} MB."); metaReq.Dispose(); yield break; } } } } catch (Exception ex) { Exception e = ex; ((MelonBase)Main.instance).LoggerInstance.Error("Error parsing metadata for " + masterId + ": " + e.Message); metaReq.Dispose(); yield break; } metaReq.Dispose(); UnityWebRequest req = UnityWebRequest.Get(GhUrl(masterId)); SetGhHeaders(req, wantRaw: true); yield return req.SendWebRequest(); if ((int)req.result != 1) { ((MelonBase)Main.instance).LoggerInstance.Error("Download failed for " + masterId + ": " + req.error); } else { File.WriteAllBytes(savePath, Il2CppArrayBase<byte>.op_Implicit((Il2CppArrayBase<byte>)(object)req.downloadHandler.data)); } _downloadingPlayers.Remove(masterId); req.Dispose(); } } public static class RigManager { private static Main instance; public static readonly Dictionary<string, CustomRig> rigs = new Dictionary<string, CustomRig>(); private static readonly HashSet<string> loadingPlayers = new HashSet<string>(); private static int activeLoads = 0; public static void Initialize(Main mainInstance) { instance = mainInstance; } public static void LogStatsForAvatar(GameObject rig) { //IL_0425: Unknown result type (might be due to invalid IL or missing references) //IL_042a: Unknown result type (might be due to invalid IL or missing references) //IL_0444: Unknown result type (might be due to invalid IL or missing references) //IL_0446: Unknown result type (might be due to invalid IL or missing references) //IL_0480: Unknown result type (might be due to invalid IL or missing references) //IL_04cf: Unknown result type (might be due to invalid IL or missing references) //IL_042e: Unknown result type (might be due to invalid IL or missing references) //IL_0433: Unknown result type (might be due to invalid IL or missing references) //IL_0437: Unknown result type (might be due to invalid IL or missing references) //IL_043c: Unknown result type (might be due to invalid IL or missing references) Instance loggerInstance = ((MelonBase)Main.instance).LoggerInstance; if ((Object)(object)rig == (Object)null) { loggerInstance.Warning("LogStatsForAvatar: rig is null"); return; } Il2CppArrayBase<SkinnedMeshRenderer> componentsInChildren = rig.GetComponentsInChildren<SkinnedMeshRenderer>(); if (componentsInChildren.Length == 0) { loggerInstance.Warning("LogStatsForAvatar: No SkinnedMeshRenderer or mesh found"); return; } int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; bool flag = false; bool flag2 = false; foreach (SkinnedMeshRenderer item in componentsInChildren) { if ((Object)(object)item.sharedMesh != (Object)null) { num += item.sharedMesh.vertexCount; } Il2CppReferenceArray<Material> sharedMaterials = ((Renderer)item).sharedMaterials; num2 += ((Il2CppArrayBase<Material>)(object)sharedMaterials).Length; foreach (Material item2 in (Il2CppArrayBase<Material>)(object)sharedMaterials) { if ((Object)(object)item2 == (Object)null) { continue; } foreach (string item3 in (Il2CppArrayBase<string>)(object)item2.GetTexturePropertyNames()) { Texture texture = item2.GetTexture(item3); if ((Object)(object)texture != (Object)null) { num3++; if (texture.width >= 4096 || texture.height >= 4096) { flag = true; loggerInstance.Warning($"[Avatar Optimization] Huge texture on '{((Object)item2).name}' ({item3}): {texture.width}x{texture.height}"); } } } Shader shader = item2.shader; int num5 = ((shader != null) ? shader.passCount : 0); num4 += num5; if (num5 > 7) { loggerInstance.Warning($"[Avatar Optimiziation] Shader '{((Object)item2.shader).name}' has {num5} passes."); } if (((Object)item2.shader).name.ToLower().Contains("tessellation")) { flag2 = true; ((MelonBase)Main.instance).LoggerInstance.Warning("[Avatar Optimization] Shader '" + ((Object)item2.shader).name + "' uses expensive features."); } } } string text = ""; if (num > 70000) { text += " High vertex count;"; } if (num2 > 5) { text += " Too many materials;"; } if (flag) { text += " Huge Textures;"; } if (flag2) { text += " Heavy Shaders;"; } if (num4 >= 32) { text += " Many Shader Passes;"; } ConsoleColor consoleColor; string text2; if (num > 70000 || num2 > 5 || flag || flag2) { consoleColor = ConsoleColor.Red; text2 = "BAD"; } else if (num > 50000 || num2 > 3) { consoleColor = ConsoleColor.Yellow; text2 = "MEDIUM"; } else { consoleColor = ConsoleColor.Green; text2 = "GOOD"; } MelonLogger.MsgPastel(consoleColor, "-------------------------------------------------------------"); loggerInstance.MsgPastel(consoleColor, $"[Avatar Optimization] {text2}: {num} verts, {num2} mat(s), {num3} texture(s)."); loggerInstance.MsgPastel(ConsoleColor.Yellow, "WARNINGS: " + (string.IsNullOrEmpty(text) ? "None" : text.TrimEnd(new char[1] { ';' }))); MelonLogger.MsgPastel(consoleColor, "-------------------------------------------------------------"); if (Main.instance.currentScene == "Gym") { if (1 == 0) { } Color val = (Color)(consoleColor switch { ConsoleColor.Green => new Color(0f, 0.5f, 0f), ConsoleColor.Yellow => Color.yellow, _ => Color.red, }); if (1 == 0) { } Color color = val; GameObject avatarOptimizationParent = Main.instance.avatarOptimizationParent; ((TMP_Text)((Component)avatarOptimizationParent.transform.GetChild(0)).GetComponent<TextMeshPro>()).text = text2; ((Graphic)((Component)avatarOptimizationParent.transform.GetChild(0)).GetComponent<TextMeshPro>()).color = color; ((TMP_Text)((Component)avatarOptimizationParent.transform.GetChild(1)).GetComponent<TextMeshPro>()).text = $"{num} verts, {num2} mat(s), {num3} texture(s)."; ((Graphic)((Component)avatarOptimizationParent.transform.GetChild(1)).GetComponent<TextMeshPro>()).color = color; ((TMP_Text)((Component)avatarOptimizationParent.transform.GetChild(2)).GetComponent<TextMeshPro>()).text = "WARNINGS: " + (string.IsNullOrEmpty(text) ? "None" : text.TrimEnd(new char[1] { ';' })); } } public static void ClearRigs() { foreach (CustomRig value in rigs.Values) { value.Apply(CustomRig.RigState.Original); if (Main.instance.perPlayerToggles.ContainsKey(value)) { Main.instance.RemoveRigFromList(value); } Object.Destroy((Object)(object)value.Root); } rigs.Clear(); } public static Stream ConvertToIl2CppStream(Stream stream) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown MemoryStream val = new MemoryStream(); byte[] array = new byte[4096]; Il2CppStructArray<byte> val2 = new Il2CppStructArray<byte>(array); int num; while ((num = stream.Read(array, 0, array.Length)) > 0) { Il2CppStructArray<byte> val3 = Il2CppStructArray<byte>.op_Implicit(array); ((Stream)val).Write(val3, 0, num); } ((Stream)val).Flush(); return (Stream)(object)val; } public static MemoryStream StreamFromFile(string path) { return new MemoryStream(File.ReadAllBytes(path)); } public static IEnumerator LoadAssetBundleFromFileAsync(string filePath, Action<AssetBundle> onLoaded) { MemoryStream ms = null; Task loadTask = Task.Run(delegate { ms = StreamFromFile(filePath); }); while (!loadTask.IsCompleted) { yield return null; } if (ms == null) { onLoaded?.Invoke(null); yield break; } Stream il2cppStream = ConvertToIl2CppStream(ms); AssetBundle bundle = AssetBundle.LoadFromStream(il2cppStream); onLoaded?.Invoke(bundle); } public static IEnumerator LoadRigForPlayer(Player player, Action<GameObject> onLoaded, bool log = true, string remoteSha = null) { object obj; if (player == null) { obj = null; } else { PlayerData data = player.Data; if (data == null) { obj = null; } else { GeneralData generalData = data.GeneralData; obj = ((generalData != null) ? generalData.PlayFabMasterId : null); } } string playerID = (string)obj; if (string.IsNullOrEmpty(playerID)) { MelonLogger.Warning("LoadRigForPlayer: playerID is null or empty"); yield break; } if ((int)player.Controller.ControllerType != 1) { if (!loadingPlayers.Add(playerID)) { MelonLogger.Msg("LoadRigForPlayer: player " + playerID + " is already loading"); yield break; } while (activeLoads >= (int)((ModSetting)Main.instance.maxConcurrentDownloads).SavedValue) { yield return null; } activeLoads++; } try { bool isLocal = player == Players.GetLocalPlayer(); string opponentPath = Path.Combine(MelonEnvironment.UserDataDirectory, "CustomAvatars", "Opponents"); if (!Directory.Exists(opponentPath)) { Directory.CreateDirectory(opponentPath); } string basePath = Path.Combine(MelonEnvironment.UserDataDirectory, "CustomAvatars"); string filePath = (isLocal ? Directory.GetFiles(basePath, "*.rumbleavatar").FirstOrDefault() : Path.Combine(opponentPath, playerID)); if (!isLocal && !File.Exists(filePath)) { if (log) { ((MelonBase)Main.instance).LoggerInstance.Msg("Downloading avatar for path " + opponentPath); } yield return MelonCoroutines.Start(RemoteAvatarLoader.DownloadToFile(playerID, filePath)); } string rigPath = (isLocal ? Directory.GetFiles(basePath, "*.rumbleavatar").FirstOrDefault() : Path.Combine(basePath, "Opponents", playerID)); if (string.IsNullOrEmpty(rigPath) || !File.Exists(rigPath)) { Instance loggerInstance = ((MelonBase)Main.instance).LoggerInstance; object obj2; if (!isLocal) { if (player == null) { obj2 = null; } else { GeneralData generalData2 = player.Data.GeneralData; obj2 = ((generalData2 != null) ? generalData2.PublicUsername : null); } if (obj2 == null) { obj2 = "unknown"; } } else { obj2 = "you"; } loggerInstance.Warning("No custom avatar found for " + (string?)obj2 + " at " + basePath); yield break; } AssetBundle rigBundle = null; yield return MelonCoroutines.Start(LoadAssetBundleFromFileAsync(rigPath, delegate(AssetBundle bundle) { rigBundle = bundle; })); AssetBundle obj3 = rigBundle; GameObject rigPrefab = ((obj3 != null) ? obj3.LoadAsset<GameObject>("Rig") : null); if ((Object)(object)rigPrefab == (Object)null) { Instance loggerInstance2 = ((MelonBase)Main.instance).LoggerInstance; object obj4; if (!isLocal) { if (player == null) { obj4 = null; } else { PlayerData data2 = player.Data; if (data2 == null) { obj4 = null; } else { GeneralData generalData3 = data2.GeneralData; obj4 = ((generalData3 != null) ? generalData3.PublicUsername : null); } } if (obj4 == null) { obj4 = "unknown"; } } else { obj4 = "local player"; } loggerInstance2.Error("Failed to load 'Rig' GameObject for " + (string?)obj4 + " from path " + rigPath); yield break; } GameObject rigInstance = Object.Instantiate<GameObject>(rigPrefab); ((Object)rigInstance).name = "RIG - " + playerID; rigInstance.transform.SetParent(Main.instance.rigParent.transform, true); if ((Object)(object)((player != null) ? player.Controller : null) == (Object)null) { ((MelonBase)Main.instance).LoggerInstance.Error("player.Controller is null"); yield break; } if ((Object)(object)((Component)player.Controller).gameObject == (Object)null) { ((MelonBase)Main.instance).LoggerInstance.Error("player.Controller.gameObject is null"); yield break; } CustomRig customRig = ((Component)player.Controller).gameObject.GetOrAddComponent<CustomRig>(); if ((Object)(object)customRig == (Object)null) { ((MelonBase)Main.instance).LoggerInstance.Error("Failed to get or add CustomRig component"); yield break; } rigs[playerID] = customRig; TextAsset jsonAsset = rigBundle.LoadAsset<TextAsset>("Config"); if ((Object)(object)jsonAsset == (Object)null) { ((MelonBase)Main.instance).LoggerInstance.Warning("Config.json not found in rig bundle. Make sure your avatar has a AvatarDescriptor that was exported."); } else { try { AvatarDescriptorExport config = JsonConvert.DeserializeObject<AvatarDescriptorExport>(jsonAsset.text); customRig.Config = config; } catch (Exception ex2) { Exception ex = ex2; ((MelonBase)Main.instance).LoggerInstance.Error("Failed to parse avatar config: " + ex.Message); } } if (customRig.Config != null) { foreach (BlendshapeDefault blendshape in customRig.Config.defaultBlendshapes) { if (blendshape.index >= 0) { customRig.MeshRenderer.SetBlendShapeWeight(blendshape.index, blendshape.weight); continue; } ((MelonBase)Main.instance).LoggerInstance.Warning("Blendshape '" + blendshape.name + "' not found on mesh '" + ((Object)customRig.MeshRenderer.sharedMesh).name + "'"); } } customRig.PlayerName = player.Data.GeneralData.PublicUsername; customRig.AvatarFilePath = filePath; rigBundle.Unload(false); if (log) { ((MelonBase)Main.instance).LoggerInstance.Msg("Loading rig for player " + playerID); } if ((Object)(object)rigInstance != (Object)null && log && (((bool)((ModSetting)Main.instance.logAvatarStats).SavedValue && isLocal) || ((bool)((ModSetting)Main.instance.logOtherAvatarStats).SavedValue && !isLocal))) { LogStatsForAvatar(rigInstance); } ApplyRigToPlayer(player, rigInstance, log); if (!isLocal) { Path.Combine(basePath, "Opponents", playerID); CustomRig rig = ((Component)player.Controller).GetComponent<CustomRig>(); Main.instance.AddRigToList(customRig); ResolveRigState(player, rig); } GameObject camObj = GameObject.Find("RumbleHud_" + playerID + "_portraitCamera"); Camera cam = ((camObj != null) ? camObj.GetComponent<Camera>() : null); if ((Object)(object)cam != (Object)null) { cam.nearClipPlane = 0.01f; } (Type.GetType("RumbleHud.Hud, RumbleHud")?.GetMethod("RegeneratePortraits", BindingFlags.Static | BindingFlags.Public))?.Invoke(null, new object[1] { Main.instance.currentScene == "Gym" }); onLoaded?.Invoke(rigInstance); } finally { activeLoads--; loadingPlayers.Remove(playerID); } } public static void ResolveRigState(Player player, CustomRig rig) { if (!(bool)((ModSetting)Main.instance.toggleOthers).Value) { rig.Apply(CustomRig.RigState.Original); return; } object obj; if (player == null) { obj = null; } else { PlayerController controller = player.Controller; obj = ((controller != null) ? ((Component)controller).GetComponent<PhotonView>() : null); } PhotonView val = (PhotonView)obj; object obj2; if (val == null) { obj2 = null; } else { Player controller2 = val.Controller; obj2 = ((controller2 != null) ? controller2.CustomProperties : null); } Hashtable val2 = (Hashtable)obj2; Object val3 = default(Object); if (val2 != null && ((Dictionary<Object, Object>)(object)val2).TryGetValue(Object.op_Implicit("CA_Avatar"), ref val3)) { ModSetting<bool> value; if (!((Il2CppObjectBase)val3).Unbox<bool>()) { rig.Apply(CustomRig.RigState.Original); } else if (Main.instance.perPlayerToggles.TryGetValue(rig, out value)) { rig.Apply(((bool)((ModSetting)value).SavedValue) ? CustomRig.RigState.Rigged : CustomRig.RigState.Original); } else { rig.Apply(CustomRig.RigState.Rigged); } } else { rig.Apply(CustomRig.RigState.Original); } } public static void ApplyRigToPlayer(Player player, GameObject rig, bool log = true) { if (player == null || (Object)(object)rig == (Object)null) { return; } ((Component)player.Controller).GetComponent<CustomRig>().CaptureRig(rig); string text = player.Data.GeneralData.PublicUsername.TrimString(); SkinnedMeshRenderer component = ((Component)((Component)player.Controller).transform.GetChild(1).GetChild(0)).GetComponent<SkinnedMeshRenderer>(); SkinnedMeshRenderer componentInChildren = rig.GetComponentInChildren<SkinnedMeshRenderer>(true); if (!((Object)(object)component == (Object)null) && !((Object)(object)componentInChildren == (Object)null)) { Transform child = ((Component)player.Controller).transform.GetChild(1).GetChild(1); ApplyRigToSMR(child, rig, ((Component)((Component)player.Controller).transform.GetChild(1)).GetComponent<Animator>(), ((Component)player.Controller).GetComponent<CustomRig>(), null, player.Controller.GetSubsystem<PlayerVisuals>()); if (log) { ((MelonBase)instance).LoggerInstance.Msg("Applied custom rig to player " + text + "."); } } } public static void ApplyRigBones(Animator rigAnimator, Animator rumbleAnimator, Transform rigRoot, Transform rumbleRoot) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Invalid comparison between Unknown and I4 //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)rigAnimator != (Object)null && rigAnimator.isHuman) { foreach (HumanBodyBones value2 in Enum.GetValues(typeof(HumanBodyBones))) { if ((int)value2 != 55) { Transform boneTransform = rigAnimator.GetBoneTransform(value2); Transform boneTransform2 = rumbleAnimator.GetBoneTransform(value2); if (!((Object)(object)boneTransform == (Object)null) && !((Object)(object)boneTransform2 == (Object)null)) { boneTransform.SetParent(boneTransform2, true); boneTransform.localPosition = Vector3.zero; boneTransform.localRotation = Quaternion.identity; boneTransform.localScale = Vector3.Scale(boneTransform.localScale, boneTransform2.localScale); ((Component)boneTransform).gameObject.AddComponent<CustomRigBone>(); } } } return; } Dictionary<string, List<Transform>> dictionary = (from t in (IEnumerable<Transform>)((Component)rumbleRoot).GetComponentsInChildren<Transform>(true) group t by ((Object)t).name).ToDictionary((IGrouping<string, Transform> g) => g.Key, (IGrouping<string, Transform> g) => g.ToList()); foreach (Transform componentsInChild in ((Component)rigRoot).GetComponentsInChildren<Transform>(true)) { if (!dictionary.TryGetValue(((Object)componentsInChild).name, out var value)) { continue; } foreach (Transform item in value) { componentsInChild.SetParent(item, true); componentsInChild.localPosition = Vector3.zero; componentsInChild.localRotation = Quaternion.identity; componentsInChild.localScale = Vector3.Scale(componentsInChild.localScale, item.localScale); ((Component)componentsInChild).gameObject.AddComponent<CustomRigBone>(); } } } public static void ApplyRigToSMR(Transform skeletonRoot, GameObject rig, Animator rumbleAnimator = null, CustomRig customRig = null, SkinnedMeshRenderer renderer = null, PlayerVisuals visuals = null) { if ((Object)(object)skeletonRoot == (Object)null || (Object)(object)rig == (Object)null) { return; } SkinnedMeshRenderer componentInChildren = rig.GetComponentInChildren<SkinnedMeshRenderer>(true); if ((Object)(object)componentInChildren == (Object)null) { return; } if ((Object)(object)renderer == (Object)null) { if ((Object)(object)customRig != (Object)null && (Object)(object)customRig.MeshRenderer != (Object)null) { ApplyRig(customRig.Root.transform, componentInChildren, customRig.MeshRenderer, customRig.OriginalMaterial); } } else { ApplyRig(rig.transform, componentInChildren, renderer, ((Renderer)renderer).material); } void ApplyRig(Transform customRigTransform, SkinnedMeshRenderer rigRenderer, SkinnedMeshRenderer playerRenderer, Material originalMaterial) { //IL_03a2: Unknown result type (might be due to invalid IL or missing references) //IL_03a9: Expected O, but got Unknown //IL_036a: Unknown result type (might be due to invalid IL or missing references) //IL_0371: Expected O, but got Unknown //IL_053e: Unknown result type (might be due to invalid IL or missing references) //IL_0548: Expected O, but got Unknown if ((Object)(object)customRig == (Object)null) { ((MelonBase)Main.instance).LoggerInstance.Error("customRig is null"); } else if ((Object)(object)skeletonRoot == (Object)null) { ((MelonBase)Main.instance).LoggerInstance.Error("skeletonRoot is null"); } else if ((Object)(object)playerRenderer == (Object)null) { ((MelonBase)Main.instance).LoggerInstance.Error("playerRenderer is null"); } else if ((Object)(object)rigRenderer == (Object)null) { ((MelonBase)Main.instance).LoggerInstance.Error("rigRenderer is null"); } else { Il2CppArrayBase<CustomRigBone> componentsInChildren = ((Component)skeletonRoot).GetComponentsInChildren<CustomRigBone>(true); if (componentsInChildren != null) { foreach (CustomRigBone item in componentsInChildren) { if ((Object)(object)item != (Object)null && (Object)(object)((Component)item).gameObject != (Object)null) { Object.DestroyImmediate((Object)(object)((Component)item).gameObject); } } } ((Renderer)playerRenderer).enabled = false; foreach (Collider componentsInChild in rig.GetComponentsInChildren<Collider>(true)) { Object.Destroy((Object)(object)componentsInChild); } Animator componentInParent = ((Component)customRigTransform).GetComponentInParent<Animator>(); ApplyRigBones(componentInParent, rumbleAnimator, rig.transform, skeletonRoot); foreach (Collider componentsInChild2 in ((Component)customRigTransform).GetComponentsInChildren<Collider>(true)) { Object.Destroy((Object)(object)componentsInChild2); } if ((Object)(object)rigRenderer.sharedMesh != (Object)null) { if (customRig.Config.swapOriginalMesh) { playerRenderer.sharedMesh = rigRenderer.sharedMesh; } else { ((MelonBase)Main.instance).LoggerInstance.Warning("rigRenderer.sharedMesh is null"); } } Il2CppReferenceArray<Transform> bones = rigRenderer.bones; if (bones != null && ((Il2CppArrayBase<Transform>)(object)bones).Length > 0) { if (customRig.Config.swapOriginalMesh) { playerRenderer.bones = rigRenderer.bones; customRig.RigBones = Il2CppArrayBase<Transform>.op_Implicit((Il2CppArrayBase<Transform>)(object)rigRenderer.bones); } } else { ((MelonBase)Main.instance).LoggerInstance.Warning("rigRenderer.bones array is null or empty"); } if ((Object)(object)((Renderer)playerRenderer).material == (Object)null) { ((MelonBase)Main.instance).LoggerInstance.Error("playerRenderer.material is null"); } else if ((Object)(object)((Renderer)rigRenderer).material == (Object)null) { ((MelonBase)Main.instance).LoggerInstance.Error("rigRenderer.material is null"); } else { Il2CppReferenceArray<Material> materials = ((Renderer)rigRenderer).materials; Material[] array = (Material[])(object)new Material[((Il2CppArrayBase<Material>)(object)materials).Length]; int num = customRig.Config?.bodyShaderSlot ?? 0; for (int i = 0; i < ((Il2CppArrayBase<Material>)(object)materials).Length; i++) { Material val = ((Il2CppArrayBase<Material>)(object)materials)[i]; bool flag = customRig.Config != null && customRig.Config.playerShaderSlots.Contains(i); Material val2; if (flag) { val2 = new Material(customRig.OriginalMaterial); Texture texture = val.GetTexture("_BaseMap"); if ((Object)(object)texture != (Object)null) { val2.SetTexture("_ColorAtlas", texture); } } else { val2 = new Material(val); } if (i == num && (Object)(object)visuals != (Object)null && customRig.IsLocal) { if (flag) { Texture texture2 = val.GetTexture("_BaseMap"); if ((Object)(object)texture2 != (Object)null) { visuals.NonHeadClippedMaterial.SetTexture("_ColorAtlas", texture2); } } else { visuals.NonHeadClippedMaterial = val; if (visuals.NonHeadClippedMaterial.HasFloat("_IsLocal")) { visuals.NonHeadClippedMaterial.SetFloat("_IsLocal", 0f); } } } if (val2.HasFloat("_IsLocal")) { val2.SetFloat("_IsLocal", customRig.IsLocal ? 1f : 0f); } array[i] = val2; } if (customRig.Config.swapOriginalMesh) { ((Renderer)playerRenderer).materials = Il2CppReferenceArray<Material>.op_Implicit(array); } else { ((Renderer)rigRenderer).materials = Il2CppReferenceArray<Material>.op_Implicit(array); ((Renderer)playerRenderer).material = customRig.OriginalMaterial; } if ((Object)(object)visuals != (Object)null && customRig.IsLocal) { customRig.RigVisualsMaterial = new Material(visuals.NonHeadClippedMaterial); ((Object)customRig.RigVisualsMaterial).hideFlags = (HideFlags)61; } if ((Object)(object)customRig != (Object)null) { if ((Object)(object)((Renderer)playerRenderer).material != (Object)null) { customRig.RigMaterials = (Material[])(object)new Material[((Il2CppArrayBase<Material>)(object)((Renderer)playerRenderer).materials).Length]; for (int j = 0; j < ((Il2CppArrayBase<Material>)(object)((Renderer)playerRenderer).materials).Count; j++) { Material val3 = ((Il2CppArrayBase<Material>)(object)((Renderer)playerRenderer).materials)[j]; customRig.RigMaterials[j] = val3; ((Object)val3).hideFlags = (HideFlags)61; } } else { ((MelonBase)Main.instance).LoggerInstance.Warning("playerRenderer.material is null while assigning to customRigComp"); } if ((Object)(object)rigRenderer.sharedMesh != (Object)null) { customRig.RigMesh = Object.Instantiate<Mesh>(rigRenderer.sharedMesh); ((Object)customRig.RigMesh).hideFlags = (HideFlags)61; } else { ((MelonBase)Main.instance).LoggerInstance.Warning("rigRenderer.sharedMesh is null while assigning to customRigComp"); } } if ((Object)(object)((Component)rigRenderer).gameObject != (Object)null && customRig.Config.swapOriginalMesh) { Object.Destroy((Object)(object)((Component)rigRenderer).gameObject); } ((Renderer)playerRenderer).enabled = true; } } } } public static Transform FindDeepChild(Transform parent, string name) { for (int i = 0; i < parent.childCount; i++) { Transform child = parent.GetChild(i); if (((Object)child).name == name) { return child; } Transform val = FindDeepChild(child, name); if ((Object)(object)val != (Object)null) { return val; } } return null; } } [Serializable] public class AvatarDescriptorExport { public enum BlinkType { None, Single, LeftRight } public bool swapOriginalMesh = true; public List<int> playerShaderSlots = new List<int>(); public int bodyShaderSlot = -1; public List<BlendshapeDefault> defaultBlendshapes = new List<BlendshapeDefault>(); public int blinkType = -1; public int blinkBlendshape = -1; public int blinkLeftBlendshape = -1; public int blinkRightBlendshape = -1; public int jawOpenBlendshape = -1; public float voiceMultiplier = 30f; public bool autoBlink = false; public Vector2 blinkInterval = Vector2.zero; public float blinkSpeed = 0.05f; } [Serializable] public class BlendshapeDefault { public string name; public int index; public float weight; } [RegisterTypeInIl2Cpp] public class GrabbableObject : MonoBehaviour { public Transform leftHand; public Transform rightHand; public Player player; public Vector3 originalPosition; public Quaternion originalRotation; public Transform originalParent; private Transform currentHand = null; private bool isGrabbed = false; private bool isLeftTouching = false; private bool isRightTouching = false; private bool wasLeftGripHeldLastFrame = false; private bool wasRightGripHeldLastFrame = false; public IEnumerator Init(Player Player) { if (Player != null) { player = Player; originalParent = ((Component)this).transform.parent; originalPosition = ((Component)this).transform.localPosition; originalRotation = ((Component)this).transform.localRotation; while ((Object)(object)player.Controller == (Object)null) { yield return null; } leftHand = ((Component)player.Controller).transform.GetChild(2).GetChild(1).GetChild(1); rightHand = ((Component)player.Controller).transform.GetChild(2).GetChild(2).GetChild(1); } } private void Update() { bool flag = player.Controller.GetSubsystem<PlayerHandPresence>().leftHandGripInput.ReadValue<float>() > 0.5f; bool flag2 = player.Controller.GetSubsystem<PlayerHandPresence>().rightHandGripInput.ReadValue<float>() > 0.5f; if (isGrabbed) { if ((!((Object)(object)currentHand == (Object)(object)leftHand) || !(LeftController.GetGrip() > 0.5f)) && (!((Object)(object)currentHand == (Object)(object)rightHand) || !(RightController.GetGrip() > 0.5f))) { Release(); } } else if (isLeftTouching && flag && !wasLeftGripHeldLastFrame) { Grab(leftHand); } else if (isRightTouching && flag2 && !wasRightGripHeldLastFrame) { Grab(rightHand); } wasLeftGripHeldLastFrame = flag; wasRightGripHeldLastFrame = flag2; } private void Grab(Transform hand) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) isGrabbed = true; currentHand = hand; ((Component)this).transform.SetParent(((Component)hand).transform); ((Component)this).transform.localPosition = Vector3.zero; ((Component)this).transform.localRotation = Quaternion.identity; } private void Release() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) isGrabbed = false; isLeftTouching = false; isRightTouching = false; currentHand = null; ((Component)this).transform.SetParent(originalParent); ((Component)this).transform.localPosition = originalPosition; ((Component)this).transform.localRotation = originalRotation; } private void OnTriggerEnter(Collider other) { MelonLogger.Msg(((Object)other).name); if ((Object)(object)((Component)other).transform == (Object)(object)leftHand) { isLeftTouching = true; } else if ((Object)(object)((Component)other).transform == (Object)(object)rightHand) { isRightTouching = true; } } private void OnTriggerExit(Collider other) { MelonLogger.Msg(((Object)other).name); if ((Object)(object)((Component)other).transform == (Object)(object)leftHand) { isLeftTouching = false; } else if ((Object)(object)((Component)other).transform == (Object)(object)rightHand) { isRightTouching = false; } } } [Flags] public enum TriggerActionType { Blendshape = 0, ToggleOn = 1, ToggleOff = 2, Toggle = 3, ToggleTemp = 4 } public struct TriggerAction { public TriggerActionType Type; public string TargetName; public GameObject TargetGameObject; public float Duration; public TriggerAction(TriggerActionType type, string targetName, float duration, GameObject targetGameObject = null) { Type = type; TargetName = targetName; Duration = duration; TargetGameObject = targetGameObject; } }