Esempio n. 1
0
        private void AddAvatar(string id)
        {
            bool changed = true;

            if (!favoriteAvatarList.Contains(id))
            {
                favoriteAvatarList.Add(id);
                changed = true;
            }
            if (!savedFavoriteAvatars.ContainsKey(id))
            {
                savedFavoriteAvatars[id] = new SerializableApiAvatar()
                {
                    id = id
                };
                changed = true;
            }
            if (changed)
            {
                Save();
            }
            if (useNetwork && !waitingForServer)
            {
                new Thread(() =>
                {
                    VRCModNetworkManager.SendRPC("slaynash.avatarfav.addavatar", id, null, (error) =>
                    {
                        addError = "Unable to favorite avatar: " + error;
                        favButton.GetComponent <Button>().interactable = true;
                    });
                }).Start();
            }
        }
Esempio n. 2
0
 private void SearchForAvatars(string text)
 {
     VRCUiPopupManagerUtils.ShowPopup("AvatarFav", "Looking for avatars");
     VRCModNetworkManager.SendRPC("slaynash.avatarfav.search", text.Trim(), () => { }, (error) => {
         VRCUiPopupManagerUtils.ShowPopup("AvatarFav", "Unable to fetch avatars:\nVRVCModNetwork returned error:\n" + error, "Close", () => VRCUiPopupManagerUtils.GetVRCUiPopupManager().HideCurrentPopup());
     });
 }
Esempio n. 3
0
        private void RemoveAvatar(string id)
        {
            var changed = false;

            if (savedFavoriteAvatars.ContainsKey(id))
            {
                savedFavoriteAvatars.Remove(id);
                changed = true;
            }
            if (favoriteAvatarList.Contains(id))
            {
                favoriteAvatarList.Remove(id);
                changed = true;
            }
            if (changed)
            {
                Save();
            }
            if (useNetwork && !waitingForServer)
            {
                new Thread(() =>
                {
                    VRCModNetworkManager.SendRPC("slaynash.avatarfav.removeavatar", id, null, (error) =>
                    {
                        addError = "Unable to unfavorite avatar: " + error;
                        favButton.GetComponent <Button>().interactable = true;
                    });
                }).Start();
            }
        }
Esempio n. 4
0
 private void OnUpdate()
 {
     if (!Initialised)
     {
         return;
     }
     VRCModNetworkManager.Update();
     VRCModNetworkStatus.Update();
     ModdedUsersManager.Update();
 }
Esempio n. 5
0
        private IEnumerator VRCToolsSetup()
        {
            VRCModLogger.Log("[VRCTools] Initialising VRCTools");

            yield return(VRCUiManagerUtils.WaitForUiManagerInit());

            VRCModLogger.Log("[VRCTools] Overwriting login button event");
            VRCUiPageAuthentication loginPage = Resources.FindObjectsOfTypeAll <VRCUiPageAuthentication>().FirstOrDefault((page) => page.gameObject.name == "LoginUserPass");

            if (loginPage != null)
            {
                Button loginButton = loginPage.transform.Find("ButtonDone (1)")?.GetComponent <Button>();
                if (loginButton != null)
                {
                    ButtonClickedEvent bce = loginButton.onClick;
                    loginButton.onClick = new ButtonClickedEvent();
                    loginButton.onClick.AddListener(() => {
                        VRCModNetworkManager.SetCredentials(GetTextFromUiInputField(loginPage.loginUserName) + ":" + GetTextFromUiInputField(loginPage.loginPassword));
                        bce?.Invoke();
                    });
                }
                else
                {
                    VRCModLogger.Log("[VRCTools] Unable to find login button in login page");
                }
            }
            else
            {
                VRCModLogger.Log("[VRCTools] Unable to find login page");
            }

            yield return(VRCModLoaderUpdater.CheckVRCModLoaderHash());

            try
            {
                VRCModNetworkStatus.Setup();
                ModConfigPage.Setup();
                ModdedUsersManager.Init();
            } catch (Exception ex)
            {
                VRCModLogger.Log("[VRCTools]" + ex.ToString());
            }
            VRCModLogger.Log("[VRCTools] Init done !");

            VRCUiPopupManagerUtils.GetVRCUiPopupManager().HideCurrentPopup();

            Initialised = true;

            if (!usingVRCMenuUtils)
            {
                VRCFlowManagerUtils.EnableVRCFlowManager();
            }

            VRCModNetworkManager.ConnectAsync();
        }
Esempio n. 6
0
 private void RequestAvatars()
 {
     new Thread(() => VRCModNetworkManager.SendRPC("slaynash.avatarfav.getavatars", "", null, (error) =>
     {
         VRCModLogger.Log("[AvatarFav] Unable to fetch avatars: Server returned " + error);
         if (error.Equals("SERVER_DISCONNECTED"))
         {
             waitingForServer = true;
         }
     })).Start();
 }
Esempio n. 7
0
 private void RemoveAvatar(string id)
 {
     new Thread(() =>
     {
         VRCModNetworkManager.SendRPC("slaynash.avatarfav.removeavatar", id, null, (error) =>
         {
             addError = "Unable to unfavorite avatar: " + error;
             favButton.GetComponent <Button>().interactable = true;
         });
     }).Start();
 }
Esempio n. 8
0
        public override void RemoteError(string error)
        {
            base.RemoteError(error);

            if (id != null)
            {
                VRCModNetworkManager.SheduleForMainThread(() =>
                {
                    SecurePlayerPrefs.DeleteKey("vrcmnw_token_" + id);
                });
            }
        }
Esempio n. 9
0
 public override void Handle(string parts)
 {
     Destroy();
     if (!parts.Equals("OK"))
     {
         string[] rpcparts = parts.Split(new char[] { ' ' }, 3);
         VRCModNetworkManager.HandleRpc(rpcparts[0], rpcparts[1], rpcparts[2]);
         WriteLine("OK");
     }
     else
     {
         onSuccess?.Invoke();
     }
 }
Esempio n. 10
0
 public override void Handle(string parts)
 {
     Destroy();
     if (parts.StartsWith("OK"))
     {
         VRCModNetworkManager.SheduleForMainThread(() =>
         {
             onSuccess?.Invoke();
         });
     }
     else
     {
         onError(parts);
     }
 }
Esempio n. 11
0
 public override void Handle(string parts)
 {
     if (parts.StartsWith("OK"))
     {
         VRCModNetworkManager.SheduleForMainThread(() =>
         {
             VRCModNetworkManager.IsAuthenticated = true;
             if (!parts.Equals("OK"))
             {
                 string token = parts.Substring(3);
                 SecurePlayerPrefs.SetString("vrcmnw_token_" + id, token, "vl9u1grTnvXA");
             }
         });
     }
     Destroy();
 }
Esempio n. 12
0
        private void OnUpdate()
        {
            if (!Initialized)
            {
                return;
            }
            VRCModNetworkManager.Update();
            VRCModNetworkStatus.Update();
            ModdedUsersManager.Update();

            /*
             * if(Input.GetKeyDown(KeyCode.F2))
             * {
             *  VRCModLogger.Log(SteamUtils.GetSteamTicket());
             * }
             */
        }
Esempio n. 13
0
        public override void RemoteError(string error)
        {
            base.RemoteError(error);

            if (id != null)
            {
                VRCModNetworkManager.SheduleForMainThread(() =>
                {
                    if (SecurePlayerPrefs.HasKey("vrcmnw_token_" + id))
                    {
                        SecurePlayerPrefs.DeleteKey("vrcmnw_token_" + id);
                        VRCModNetworkManager.userUuid = "";
                    }
                });
            }
            VRCModNetworkManager.authError = error;
        }
Esempio n. 14
0
        internal static void Init()
        {
            if (Environment.CommandLine.Contains("--vrctools.enablenameplateicons"))
            {
                enableNameplateIcons = true;
            }

            VRCModNetworkManager.SetRPCListener("slaynash.vrctools.moddedplayerlistonjoin", OnModdedplayerlistonjoinReceived);
            VRCModNetworkManager.SetRPCListener("slaynash.vrctools.moddedplayerjoined", OnModdedplayerjoinReceived);
            VRCModNetworkManager.SetRPCListener("slaynash.vrctools.moddedplayerleft", OnModdedplayerleftReceived);

            userProperty = typeof(Player).GetProperties(BindingFlags.Public | BindingFlags.Instance).First((pi) => pi.PropertyType == typeof(APIUser));

            Texture2D tex = new Texture2D(2, 2);

            Texture2DUtils.LoadImage(tex, Convert.FromBase64String(ImageDatas.VRCTOOLS_LOGO));
            vrctoolsSprite = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(0.5f, 0.5f));
        }
        private static IEnumerator AddAvatar(string id, string name)
        {
            bool done = false;

            VRCModNetworkManager.SendRPC("slaynash.avatarfav.addavatar", id, () =>
            {
                VRCModLogger.Log("[VRCheatAvatarfileImporter] Avatar " + name + " successfully added");
                importedAvatars++;
                done = true;
            }, (error) =>
            {
                VRCModLogger.Log("[VRCheatAvatarfileImporter] Unable to add the avatar " + name + ": VRCMNW Server returned error: " + error);
                done = true;
            });
            while (!done)
            {
                yield return(null);
            }
        }
Esempio n. 16
0
        public override void Handle(string parts)
        {
            Destroy();
            if (parts.StartsWith("OK"))
            {
                VRCModNetworkManager.SheduleForMainThread(() =>
                {
                    int returnValue = int.Parse(parts.Split(new[] { ' ' }, 2)[1]);
                    VRCModNetworkManager.IsAuthenticated = true;

                    VRCModNetworkManager.VRCAuthStatus = returnValue;
                    onSuccess?.Invoke();
                });
            }
            else
            {
                onError(parts);
            }
        }
Esempio n. 17
0
        private static IEnumerator CheckForPermissions()
        {
            if (!ModPrefs.GetBool("vrctools", "remoteauthcheckasked"))
            {
                VRCModLogger.Log("[VRCTools] Asking for auth");
                yield return(ShowAuthAgreePopup());

                ModPrefs.SetBool("vrctools", "remoteauthcheckasked", true);
            }
            if (ModPrefs.GetBool("vrctools", "remoteauthcheck"))
            {
                VRCModNetworkManager.ConnectAsync();
                VRCModLogger.Log("[VRCTools] Key remoteauthcheck found (true)");
                yield return(AvatarFavUpdater.CheckForAvatarFavUpdate());
            }
            else
            {
                VRCModLogger.Log("[VRCTools] Key remoteauthcheck found (false)");
            }
        }
Esempio n. 18
0
        public void OnUpdate()
        {
            if (!initialised)
            {
                return;
            }

            lock (actions)
            {
                foreach (Action a in actions)
                {
                    try
                    {
                        a();
                    }
                    catch (Exception e)
                    {
                        VRCModLogger.Log("[AvatarFav] Error while calling action from main thread: " + e);
                    }
                }
                actions.Clear();
            }

            try
            {
                //Update list if element is active
                if (favList.gameObject.activeInHierarchy)
                {
                    lock (favoriteAvatarList)
                    {
                        if (avatarAvailables)
                        {
                            avatarAvailables = false;
                            favList.ClearSpecificList();

                            if (newAvatarsFirst)
                            {
                                List <string> favReversed = favoriteAvatarList.ToList();
                                favReversed.Reverse();
                                favList.specificListIds = favReversed.ToArray();
                            }
                            else
                            {
                                favList.specificListIds = favoriteAvatarList.ToArray();
                            }


                            favList.Refresh();

                            freshUpdate = true;
                        }
                    }
                }

                if (pageAvatar.avatar != null && pageAvatar.avatar.apiAvatar != null && CurrentUserUtils.GetGetCurrentUser().GetValue(null) != null && !currentUiAvatarId.Equals(pageAvatar.avatar.apiAvatar.id) || freshUpdate)
                {
                    currentUiAvatarId = pageAvatar.avatar.apiAvatar.id;

                    bool favorited = favoriteAvatarList.Contains(currentUiAvatarId);

                    if (favorited)
                    {
                        favButtonText.text = "Unfavorite";
                    }
                    else
                    {
                        favButtonText.text = "Favorite";
                    }

                    if ((!pageAvatar.avatar.apiAvatar.releaseStatus.Equals("public") && !favorited) || pageAvatar.avatar.apiAvatar.authorId == APIUser.CurrentUser.id)
                    {
                        favButton.gameObject.SetActive(false);
                        avatarModel.localPosition = baseAvatarModelPosition;
                    }
                    else
                    {
                        favButton.gameObject.SetActive(true);
                        avatarModel.localPosition = baseAvatarModelPosition + new Vector3(0, 60, 0);
                    }
                }

                //Show returned error if exists
                if (addError != null)
                {
                    VRCUiPopupManagerUtils.ShowPopup("Error", addError, "Close", () => VRCUiPopupManagerUtils.GetVRCUiPopupManager().HideCurrentPopup());
                    addError = null;
                }


                if (RoomManager.currentRoom != null && RoomManager.currentRoom.id != null && RoomManager.currentRoom.currentInstanceIdOnly != null)
                {
                    if (currentRoom == null)
                    {
                        currentRoom = RoomManager.currentRoom;

                        if (currentRoom.releaseStatus != "public")
                        {
                            VRCModLogger.Log("[AvatarFav] Current world release status isn't public. Pedestal scan disabled.");
                        }
                        else
                        {
                            VRC_AvatarPedestal[] pedestalsInWorld = GameObject.FindObjectsOfType <VRC_AvatarPedestal>();
                            VRCModLogger.Log("[AvatarFav] Found " + pedestalsInWorld.Length + " VRC_AvatarPedestal in current world");
                            string dataToSend = currentRoom.id;
                            foreach (VRC_AvatarPedestal p in pedestalsInWorld)
                            {
                                if (p.blueprintId == null || p.blueprintId == "")
                                {
                                    continue;
                                }

                                dataToSend += ";" + p.blueprintId;
                            }

                            VRCModNetworkManager.SendRPC("slaynash.avatarfav.avatarsinworld", dataToSend);
                        }
                    }
                }
                else
                {
                    currentRoom = null;
                }
            }
            catch (Exception e)
            {
                VRCModLogger.Log("[AvatarFav] [ERROR] " + e.ToString());
            }
            freshUpdate = false;
        }
Esempio n. 19
0
        private IEnumerator VRCToolsSetup()
        {
            VRCModLogger.Log("[VRCTools] Initialising VRCTools");
            VRCModLogger.Log("[VRCTools] Current scene: " + SceneManager.GetActiveScene().name + "(index: " + SceneManager.GetActiveScene().buildIndex + ", path: " + SceneManager.GetActiveScene().path + ")");
            VRCModLogger.Log("[VRCTools] ModComponent Sibling index: " + ModComponent.Instance.transform.GetSiblingIndex());
            VRCModLogger.Log("[VRCTools] Root gameobjects:");
            foreach (GameObject g in SceneManager.GetActiveScene().GetRootGameObjects())
            {
                VRCModLogger.Log(" - " + g);
            }
            VRCModLogger.Log("[VRCTools] Call trace - THIS IS NOT AN ERROR:");
            VRCModLogger.Log(new System.Diagnostics.StackTrace().ToString());
            initializing = true;

            yield return(VRCUiManagerUtils.WaitForUiManagerInit());

            if (!HarmonyLoaded())
            {
                bool waitforpopup = true;
                VRCUiPopupManagerUtils.ShowPopup("VRCTools", "Missing library: Harmony. Please install it using the VRChat Mod Manager (see #how-to on discord.gg/rCqKSvR)", "Close game", () => Application.Quit(), "Ignore", () => waitforpopup = false);
                while (waitforpopup)
                {
                    yield return(null);
                }

                Initialized = true;
                if (!usingVRCMenuUtils)
                {
                    VRCFlowManagerUtils.EnableVRCFlowManager();
                }

                yield break;
            }

            VRCModLogger.Log("[VRCTools] Overwriting login button event");
            VRCUiPageAuthentication loginPage = Resources.FindObjectsOfTypeAll <VRCUiPageAuthentication>().FirstOrDefault((page) => page.gameObject.name == "LoginUserPass");

            if (loginPage != null)
            {
                Button loginButton = loginPage.transform.Find("ButtonDone (1)")?.GetComponent <Button>();
                if (loginButton != null)
                {
                    ButtonClickedEvent bce = loginButton.onClick;
                    loginButton.onClick = new ButtonClickedEvent();
                    loginButton.onClick.AddListener(() => {
                        VRCModNetworkManager.SetCredentials(Uri.EscapeDataString(GetTextFromUiInputField(loginPage.loginUserName)) + ":" + Uri.EscapeDataString(GetTextFromUiInputField(loginPage.loginPassword)));
                        bce?.Invoke();
                    });
                }
                else
                {
                    VRCModLogger.Log("[VRCTools] Unable to find login button in login page");
                }
            }
            else
            {
                VRCModLogger.Log("[VRCTools] Unable to find login page");
            }

            yield return(VRCModLoaderUpdater.CheckVRCModLoaderHash());

            yield return(VRCToolsAutoUpdater.CheckAndUpdate());

            try
            {
                VRCModNetworkStatus.Setup();
                VRCModNetworkLogin.SetupVRCModNetworkLoginPage();
                ModConfigPage.Setup();
                ModdedUsersManager.Init();
            } catch (Exception ex)
            {
                VRCModLogger.Log("[VRCTools]" + ex.ToString());
            }

            VRCModLogger.Log("[VRCTools] Injecting VRCModNetwork login page");
            VRCModNetworkLogin.InjectVRCModNetworkLoginPage();

            yield return(VRCModNetworkManager.ConnectInit());

            VRCUiPopupManagerUtils.GetVRCUiPopupManager().HideCurrentPopup();

            Initialized  = true;
            initializing = false;

            if (!usingVRCMenuUtils)
            {
                VRCFlowManagerUtils.EnableVRCFlowManager();
            }
        }
Esempio n. 20
0
        private IEnumerator VRCToolsSetup()
        {
            initialising = true;
            VRCModLogger.Log("[VRCTools] Initialising VRCTools");
            try
            {
                OculusUtils.ApplyPatches();
            }
            catch (Exception e)
            {
                VRCModLogger.Log("[VRCTools] Error while applying Oculus patches: " + e);
            }
            yield return(VRCUiManagerUtils.WaitForUiManagerInit());

            VRCModLogger.Log("[VRCTools] Overwriting login button event");
            VRCUiPageAuthentication[] authpages = Resources.FindObjectsOfTypeAll <VRCUiPageAuthentication>();
            VRCUiPageAuthentication   loginPage = authpages.First((page) => page.gameObject.name == "LoginUserPass");

            if (loginPage != null)
            {
                Button loginButton = loginPage.transform.Find("ButtonDone (1)")?.GetComponent <Button>();
                if (loginButton != null)
                {
                    ButtonClickedEvent bce = loginButton.onClick;
                    loginButton.onClick = new ButtonClickedEvent();
                    loginButton.onClick.AddListener(() => {
                        VRCModNetworkManager.SetCredentials(GetTextFromUiInputField(loginPage.loginUserName) + ":" + GetTextFromUiInputField(loginPage.loginPassword));
                        bce?.Invoke();
                    });
                }
                else
                {
                    VRCModLogger.Log("[VRCTools] Unable to find login button in login page");
                }
            }
            else
            {
                VRCModLogger.Log("[VRCTools] Unable to find login page");
            }

            yield return(DependenciesDownloader.CheckDownloadFiles());

            yield return(VRCModLoaderUpdater.CheckVRCModLoaderHash());

            if (ModPrefs.GetBool("vrctools", "enablediscordrichpresence"))
            {
                DiscordManager.Init();
            }

            yield return(AvatarFavUpdater.CheckForAvatarFavUpdate());

            VRCModNetworkStatus.Setup();
            ModConfigPage.Setup();
            ModdedUsersManager.Init();

            /*
             * if (ApiCredentials.Load())
             * {
             *  VRCModLogger.Log("ApiCredentials.GetAuthTokenProviderUserId() => " + ApiCredentials.());
             *  if (!SecurePlayerPrefs.HasKey("vrcmnw_token_" + ApiCredentials.GetAuthTokenProviderUserId()))
             *  {
             *      ApiCredentials.Clear();
             *  }
             * }
             */
            ApiCredentials.Clear();


            VRCModLogger.Log("[VRCTools] Init done !");

            VRCUiPopupManagerUtils.GetVRCUiPopupManager().HideCurrentPopup();

            VRCFlowManagerUtils.EnableVRCFlowManager();

            initialising = false;
            Initialised  = true;

            VRCModNetworkManager.ConnectAsync();
        }
Esempio n. 21
0
        private IEnumerator VRCToolsSetup()
        {
            VRCModLogger.Log("[VRCTools] Waiting for UI Manager...");
            yield return(VRCUiManagerUtils.WaitForUiManagerInit());

            VRCModLogger.Log("[VRCTools] UIManager initialised ! Resuming setup");

            VRCModLogger.Log("[VRCTools] Overwriting login button event");
            VRCUiPageAuthentication[] authpages = Resources.FindObjectsOfTypeAll <VRCUiPageAuthentication>();
            VRCUiPageAuthentication   loginPage = authpages.First((page) => page.gameObject.name == "LoginUserPass");

            if (loginPage != null)
            {
                Button loginButton = loginPage.transform.Find("ButtonDone (1)")?.GetComponent <Button>();
                if (loginButton != null)
                {
                    ButtonClickedEvent bce = loginButton.onClick;
                    loginButton.onClick = new ButtonClickedEvent();
                    loginButton.onClick.AddListener(() => {
                        VRCModNetworkManager.SetCredentials(GetTextFromUiInputField(loginPage.loginUserName) + ":" + GetTextFromUiInputField(loginPage.loginPassword));
                        bce?.Invoke();
                    });
                }
                else
                {
                    VRCModLogger.Log("[VRCTools] Unable to find login button in login page");
                }
            }
            else
            {
                VRCModLogger.Log("[VRCTools] Unable to find login page");
            }

            VRCModLogger.Log("[VRCTools] CheckDownloadFiles");
            yield return(DependenciesDownloader.CheckDownloadFiles());

            VRCModLogger.Log("[VRCTools] CheckVRCModLoaderHash");
            yield return(VRCModLoaderUpdater.CheckVRCModLoaderHash());

            if (ModPrefs.GetBool("vrctools", "enablediscordrichpresence"))
            {
                VRCModLogger.Log("[VRCTools] DiscordManager Init");
                DiscordManager.Init();
            }
            VRCModLogger.Log("[VRCTools] CheckForPermissions");
            yield return(CheckForPermissions());

            VRCModLogger.Log("[VRCTools] VRCModNetworkStatus Setup");
            VRCModNetworkStatus.Setup();
            VRCModLogger.Log("[VRCTools] ModConfigPage Setup");
            ModConfigPage.Setup();
            VRCModLogger.Log("[VRCTools] ModdedUsersManager Init");
            ModdedUsersManager.Init();

            VRCUiManagerUtils.OnPageShown += (page) => {
                VRCModLogger.Log("[VRCTools] OnPageShown: " + page.screenType + " " + (string.IsNullOrEmpty(page.displayName) ? "" : page.displayName + " ") + "(" + page.GetType() + ")");
            };

            VRCModLogger.Log("[VRCTools] Init done !");

            VRCFlowManagerUtils.EnableVRCFlowManager();

            initialising = false;
            Initialised  = true;

            //DebugUtils.PrintHierarchy(VRCUiManagerUtils.GetVRCUiManager().transform.root, 0);
        }
Esempio n. 22
0
        void OnLevelWasLoaded(int level)
        {
            VRCModLogger.Log("[AvatarFav] OnLevelWasLoaded (" + level + ")");
            if (level == (Application.platform == RuntimePlatform.WindowsPlayer ? 1 : 2) && !alreadyLoaded)
            {
                alreadyLoaded = true;

                if (instance != null)
                {
                    Debug.LogWarning("[AvatarFav] Trying to load the same plugin two time !");
                    return;
                }
                instance = this;
                VRCModLogger.Log("[AvatarFav] Adding button to UI - Looking up for Change Button");
                // Add a "Favorite" / "Unfavorite" button over the "Choose" button of the AvatarPage
                Transform changeButton = null;
                pageAvatar = Resources.FindObjectsOfTypeAll <PageAvatar>().First(p => (changeButton = p.transform.Find("Change Button")) != null);

                VRCModLogger.Log("[AvatarFav] Adding avatar check on Change button");

                baseChooseEvent = changeButton.GetComponent <Button>().onClick;

                changeButton.GetComponent <Button>().onClick = new Button.ButtonClickedEvent();
                changeButton.GetComponent <Button>().onClick.AddListener(() =>
                {
                    VRCModLogger.Log("[AvatarFav] Fetching avatar releaseStatus for " + pageAvatar.avatar.apiAvatar.name + " (" + pageAvatar.avatar.apiAvatar.id + ")");
                    ModManager.StartCoroutine(CheckAndWearAvatar());
                });



                VRCModLogger.Log("[AvatarFav] Adding favorite button to UI - Duplicating Button");
                favButton      = UnityUiUtils.DuplicateButton(changeButton, "Favorite", new Vector2(0, 80));
                favButton.name = "ToggleFavorite";
                favButton.gameObject.SetActive(false);
                favButtonText = favButton.Find("Text").GetComponent <Text>();
                favButton.GetComponent <Button>().interactable = false;

                favButton.GetComponent <Button>().onClick.AddListener(ToggleAvatarFavorite);

                VRCModLogger.Log("[AvatarFav] Storing default AvatarModel position");
                avatarModel             = pageAvatar.transform.Find("AvatarModel");
                baseAvatarModelPosition = avatarModel.localPosition;


                FileInfo[] files = new DirectoryInfo(Environment.CurrentDirectory).GetFiles("Avatars.txt", SearchOption.AllDirectories);
                VRCModLogger.Log("[AvatarFavMod] Found " + files.Length + " Avatars.txt");
                if (files.Length > 0)
                {
                    VRCModLogger.Log("[AvatarFav] Adding import button to UI - Duplicating Button");
                    Transform importButton = UnityUiUtils.DuplicateButton(changeButton, "Import Avatars", new Vector2(0, 0));
                    importButton.name = "ImportAvatars";

                    importButton.GetComponent <RectTransform>().anchoredPosition = new Vector2(560, 371);

                    importButton.GetComponent <Button>().onClick.AddListener(() =>
                    {
                        VRCUiPopupManagerUtils.ShowPopup("AvatarFav", "Do you want to import the public avatars from your VRCheat avatar list ?",
                                                         "Yes", () =>
                        {
                            ModManager.StartCoroutine(VRCheatAvatarfileImporter.ImportAvatarfile());
                        },
                                                         "No", () =>
                        {
                            VRCUiPopupManagerUtils.GetVRCUiPopupManager().HideCurrentPopup();
                        });
                        VRCheatAvatarfileImporter.ImportAvatarfile();
                    });
                }


                favList = AvatarPageHelper.AddNewList("Favorite Avatar List (Unofficial)", 1);



                // Get Getter of VRCUiContentButton.PressAction
                applyAvatarField = typeof(VRCUiContentButton).GetFields(BindingFlags.NonPublic | BindingFlags.Instance).First((field) => field.FieldType == typeof(Action));

                VRCModLogger.Log("[AvatarFav] Registering VRCModNetwork events");
                VRCModNetworkManager.OnAuthenticated += () =>
                {
                    RequestAvatars();
                };

                VRCModNetworkManager.SetRPCListener("slaynash.avatarfav.serverconnected", (senderId, data) => { if (waitingForServer)
                                                                                                                {
                                                                                                                    RequestAvatars();
                                                                                                                }
                                                    });
                VRCModNetworkManager.SetRPCListener("slaynash.avatarfav.error", (senderId, data) => addError = data);
                VRCModNetworkManager.SetRPCListener("slaynash.avatarfav.avatarlistupdated", (senderId, data) =>
                {
                    lock (favoriteAvatarList)
                    {
                        // Update Ui
                        favButton.GetComponent <Button>().interactable = true;
                        SerializableApiAvatar[] serializedAvatars      = SerializableApiAvatar.ParseJson(data);
                        favoriteAvatarList.Clear();
                        foreach (SerializableApiAvatar serializedAvatar in serializedAvatars)
                        {
                            favoriteAvatarList.Add(serializedAvatar.id);
                        }

                        avatarAvailables = true;
                    }
                });



                VRCModLogger.Log("[AvatarFav] Adding avatar search list");

                if (pageAvatar != null)
                {
                    VRCUiPageHeader pageheader = VRCUiManagerUtils.GetVRCUiManager().GetComponentInChildren <VRCUiPageHeader>(true);
                    if (pageheader != null)
                    {
                        searchbar = pageheader.searchBar;
                        if (searchbar != null)
                        {
                            VRCModLogger.Log("[AvatarFav] creating avatar search list");
                            avatarSearchList = AvatarPageHelper.AddNewList("Search Results", 0);
                            avatarSearchList.ClearAll();
                            avatarSearchList.gameObject.SetActive(false);
                            avatarSearchList.collapsedCount   = 50;
                            avatarSearchList.expandedCount    = 50;
                            avatarSearchList.collapseRows     = 5;
                            avatarSearchList.extendRows       = 5;
                            avatarSearchList.contractedHeight = 850f;
                            avatarSearchList.expandedHeight   = 850f;
                            avatarSearchList.GetComponent <LayoutElement>().minWidth = 1600f;
                            avatarSearchList.GetComponentInChildren <GridLayoutGroup>(true).constraintCount = 5;
                            avatarSearchList.expandButton.image.enabled = false;

                            VRCModLogger.Log("[AvatarFav] Overwriting search button");
                            VRCUiManagerUtils.OnPageShown += (page) =>
                            {
                                if (page.GetType() == typeof(PageAvatar))
                                {
                                    UiVRCList[] lists = page.GetComponentsInChildren <UiVRCList>(true);
                                    foreach (UiVRCList list in lists)
                                    {
                                        if (list != avatarSearchList && (list.GetType() != typeof(UiAvatarList) || ((int)categoryField.GetValue(list)) != 0))
                                        {
                                            list.gameObject.SetActive(true);
                                        }
                                        else
                                        {
                                            list.gameObject.SetActive(false);
                                        }
                                    }
                                    VRCModLogger.Log("[AvatarFav] PageAvatar shown. Enabling searchbar next frame");
                                    ModManager.StartCoroutine(EnableSearchbarNextFrame());
                                }
                            };

                            VRCModNetworkManager.SetRPCListener("slaynash.avatarfav.searchresults", (senderid, data) =>
                            {
                                AddMainAction(() =>
                                {
                                    if (data.StartsWith("ERROR"))
                                    {
                                        VRCUiPopupManagerUtils.ShowPopup("AvatarFav", "Unable to fetch avatars: Server returned error: " + data.Substring("ERROR ".Length), "Close", () => VRCUiPopupManagerUtils.GetVRCUiPopupManager().HideCurrentPopup());
                                    }
                                    else
                                    {
                                        avatarSearchList.ClearSpecificList();
                                        if (!avatarSearchList.gameObject.activeSelf)
                                        {
                                            UiVRCList[] lists = pageAvatar.GetComponentsInChildren <UiVRCList>(true);
                                            foreach (UiVRCList list in lists)
                                            {
                                                if (list != avatarSearchList)
                                                {
                                                    list.gameObject.SetActive(false);
                                                }
                                            }
                                        }

                                        SerializableApiAvatar[] serializedAvatars = SerializableApiAvatar.ParseJson(data);

                                        string[] avatarsIds = new string[serializedAvatars.Length];

                                        for (int i = 0; i < serializedAvatars.Length; i++)
                                        {
                                            avatarsIds[i] = serializedAvatars[i].id;
                                        }

                                        avatarSearchList.specificListIds = avatarsIds;
                                        if (avatarSearchList.gameObject.activeSelf)
                                        {
                                            avatarSearchList.Refresh();
                                        }
                                        else
                                        {
                                            avatarSearchList.gameObject.SetActive(true);
                                        }
                                    }
                                });
                            });
                        }
                        else
                        {
                            VRCModLogger.LogError("[AvatarFav] Unable to find search bar");
                        }
                    }
                    else
                    {
                        VRCModLogger.LogError("[AvatarFav] Unable to find page header");
                    }
                }
                else
                {
                    VRCModLogger.LogError("[AvatarFav] Unable to find avatar page");
                }



                VRCModLogger.Log("[AvatarFav] AvatarFav Initialised !");
                initialised = true;
            }
        }