├── .github ├── FUNDING.yml └── workflows │ └── dotnet.yml ├── .gitignore ├── Docs └── README.md ├── LICENSE ├── PlagueButtonAPI ├── ExampleButtonAPIUsage │ ├── ExampleButtonAPIUsage.csproj │ ├── ExampleButtonAPIUsageMain.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ └── Utils.cs ├── PlagueButtonAPI.sln └── PlagueButtonAPI │ ├── Controls │ ├── Base Classes │ │ ├── Button.cs │ │ ├── ControlWithText.cs │ │ ├── GenericControl.cs │ │ └── Toggle.cs │ ├── Buttons │ │ ├── Label.cs │ │ ├── SimpleSingleButton.cs │ │ ├── SingleButton.cs │ │ ├── Toggles │ │ │ └── ToggleButton.cs │ │ └── WingSingleButton.cs │ ├── Grouping │ │ ├── ButtonGroup.cs │ │ └── CollapsibleButtonGroup.cs │ ├── Slider.cs │ └── Tab.cs │ ├── External Libraries │ ├── ConfigLib.cs │ ├── IL2CPPAssetBundle.cs │ └── VRCUtils │ │ └── VRCUtils.cs │ ├── Hooks │ └── Hooks.cs │ ├── Main │ ├── ButtonAPI.cs │ └── TransformHelper.cs │ ├── Misc │ ├── ComponentManager.cs │ ├── CustomInputPickup.cs │ ├── Extensions.cs │ ├── MelonLoaderEvents.cs │ ├── PriorityAttribute.cs │ ├── QuickMenuPopup.cs │ └── Utils.cs │ ├── Mod.cs │ ├── Pages │ └── MenuPage.cs │ ├── PlagueButtonAPI.csproj │ ├── Properties │ └── AssemblyInfo.cs │ └── Resources │ └── keyboard.asset ├── README.md └── References ├── ExampleButtonAPIUsage ├── Assembly-CSharp-firstpass.dll ├── Assembly-CSharp.dll ├── DataModel.dll ├── Il2CppSystem.Core.dll ├── Il2CppSystem.dll ├── Il2Cppmscorlib.dll ├── MelonLoader.dll ├── UIExpansionKit.dll ├── UnhollowerBaseLib.dll ├── UnhollowerRuntimeLib.dll ├── Unity.TextMeshPro.dll ├── UnityEngine.AssetBundleModule.dll ├── UnityEngine.CoreModule.dll ├── UnityEngine.Il2CppImageConversionManager.dll ├── UnityEngine.InputLegacyModule.dll ├── UnityEngine.TextRenderingModule.dll ├── UnityEngine.UI.dll ├── UnityEngine.UIElementsModule.dll ├── UnityEngine.UIModule.dll ├── UnityEngine.dll ├── VRC.UI.Core.dll ├── VRC.UI.Elements.dll ├── VRC.UI.Shared.dll ├── VRCCore-Editor.dll ├── VRCCore-Standalone.dll ├── VRCSDK2.dll ├── VRCSDK3A.dll ├── VRCSDKBase.dll └── VRChatUtilityKit.dll └── PlagueButtonAPI ├── Assembly-CSharp-firstpass.dll ├── Assembly-CSharp.dll ├── DataModel.dll ├── Il2CppSystem.Core.dll ├── Il2CppSystem.dll ├── Il2Cppmscorlib.dll ├── MelonLoader.dll ├── Newtonsoft.Json.dll ├── System.Windows.Forms.dll ├── UnhollowerBaseLib.dll ├── UnhollowerRuntimeLib.dll ├── Unity.TextMeshPro.dll ├── UnityEngine.AssetBundleModule.dll ├── UnityEngine.CoreModule.dll ├── UnityEngine.Il2CppImageConversionManager.dll ├── UnityEngine.InputLegacyModule.dll ├── UnityEngine.TextRenderingModule.dll ├── UnityEngine.UI.dll ├── UnityEngine.UIElementsModule.dll ├── UnityEngine.UIModule.dll ├── UnityEngine.VRModule.dll ├── UnityEngine.XRModule.dll ├── UnityEngine.dll ├── VRC.UI.Core.dll ├── VRC.UI.Elements.dll ├── VRC.UI.Shared.dll ├── VRCCore-Editor.dll ├── VRCCore-Standalone.dll ├── VRCSDK2.dll └── VRCSDKBase.dll /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | custom: https://VRCAntiCrash.com/Pay 2 | -------------------------------------------------------------------------------- /.github/workflows/dotnet.yml: -------------------------------------------------------------------------------- 1 | name: .NET 2 | 3 | on: 4 | push: 5 | branches: new-ui 6 | paths: 7 | - 'PlagueButtonAPI/**' 8 | - 'References/**' 9 | - '.github/workflows/**' 10 | 11 | jobs: 12 | build: 13 | runs-on: windows-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v2 17 | 18 | - name: Setup MSBuild 19 | uses: microsoft/setup-msbuild@v1 20 | 21 | - name: Build Solution 22 | run: | 23 | msbuild.exe PlagueButtonAPI/PlagueButtonAPI.sln /p:DeleteExistingFiles=True /p:platform="Any CPU" /p:configuration="Normal" 24 | 25 | - name: Upload PlagueButtonAPI Artifact 26 | uses: actions/upload-artifact@v2 27 | with: 28 | name: PlagueButtonAPI.dll 29 | path: PlagueButtonAPI/PlagueButtonAPI/bin/Debug/PlagueButtonAPI.dll 30 | 31 | - name: Upload PlagueButtonAPI PDB Artifact 32 | uses: actions/upload-artifact@v2 33 | with: 34 | name: PlagueButtonAPI.pdb 35 | path: PlagueButtonAPI/PlagueButtonAPI/bin/Debug/PlagueButtonAPI.pdb 36 | 37 | - name: Upload ExampleButtonAPIUsage Artifact 38 | uses: actions/upload-artifact@v2 39 | with: 40 | name: ExampleButtonAPIUsage.dll 41 | path: PlagueButtonAPI/ExampleButtonAPIUsage/bin/Debug/ExampleButtonAPIUsage.dll 42 | 43 | - name: Delete Old Releases 44 | uses: dev-drprasad/delete-older-releases@v0.2.0 45 | with: 46 | keep_latest: 0 47 | delete_tags: true 48 | env: 49 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 50 | 51 | - name: Get current date 52 | id: date 53 | run: echo "::set-output name=date::$(date +'%d/%m/%Y %H:%M')" 54 | 55 | - name: Create A Release 56 | uses: actions/create-release@v1 57 | id: create_release 58 | with: 59 | draft: false 60 | prerelease: false 61 | release_name: Latest Build [${{ steps.date.outputs.date }}] 62 | tag_name: ${{ github.run_id }} 63 | env: 64 | GITHUB_TOKEN: ${{ github.token }} 65 | 66 | - name: Add PlagueButtonAPI.dll To Release 67 | uses: actions/upload-release-asset@v1 68 | env: 69 | GITHUB_TOKEN: ${{ github.token }} 70 | with: 71 | upload_url: ${{ steps.create_release.outputs.upload_url }} 72 | asset_path: PlagueButtonAPI/PlagueButtonAPI/bin/Debug/PlagueButtonAPI.dll 73 | asset_name: PlagueButtonAPI.dll 74 | asset_content_type: application/x-msdownload 75 | 76 | - name: Add PlagueButtonAPI.dll To Release 77 | uses: actions/upload-release-asset@v1 78 | env: 79 | GITHUB_TOKEN: ${{ github.token }} 80 | with: 81 | upload_url: ${{ steps.create_release.outputs.upload_url }} 82 | asset_path: PlagueButtonAPI/ExampleButtonAPIUsage/bin/Debug/ExampleButtonAPIUsage.dll 83 | asset_name: ExampleButtonAPIUsage.dll 84 | asset_content_type: application/x-msdownload 85 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | PlagueButtonAPIExample/.vs/PlagueButtonAPIExample/v15/.suo 3 | *.lock 4 | *.ide 5 | *.ide-shm 6 | *.ide-wal 7 | *.cache 8 | PlagueButtonAPIExample/PlagueButtonAPIExample/obj/Normal/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs 9 | PlagueButtonAPIExample/PlagueButtonAPIExample/obj/Normal/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs 10 | PlagueButtonAPIExample/PlagueButtonAPIExample/obj/Normal/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs 11 | PlagueButtonAPIExample/PlagueButtonAPIExample/obj/VRChat Mods Folder/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs 12 | PlagueButtonAPIExample/PlagueButtonAPIExample/obj/VRChat Mods Folder/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs 13 | PlagueButtonAPIExample/PlagueButtonAPIExample/obj/VRChat Mods Folder/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs 14 | PlagueButtonAPIExample/PlagueButtonAPIExample/PlagueButtonAPIExample.csproj 15 | *.pdb 16 | PlagueButtonAPIExample/PlagueButtonAPIExample/obj/Normal/PlagueButtonAPIExample.csproj.FileListAbsolute.txt 17 | PlagueButtonAPIExample/PlagueButtonAPIExample/obj/VRChat Mods Folder/PlagueButtonAPIExample.csproj.FileListAbsolute.txt 18 | PlagueButtonAPIExample/PlagueButtonAPIExample/obj/VRChat Mods Folder/build.force 19 | /PlagueButtonAPIExample/ExampleButtonAPIUsage/obj/Release 20 | *.suo 21 | /PlagueButtonAPIExample/PlagueButtonAPI/obj 22 | /PlagueButtonAPI/ExampleButtonAPIUsage/obj/Release 23 | /PlagueButtonAPI/PlagueButtonAPI/obj 24 | /PlagueButtonAPI/PlagueButtonAPI/bin/Debug 25 | /PlagueButtonAPI/ExampleButtonAPIUsage/obj/Debug 26 | /PlagueButtonAPI/ExampleButtonAPIUsage/obj/VRChat Mods Folder 27 | *.htm 28 | /PlagueButtonAPI/ExampleButtonAPIUsage/obj/Normal 29 | /PlagueButtonAPI/ExampleButtonAPIUsage/ExampleButtonAPIUsage.csproj.user 30 | /PlagueButtonAPI/PlagueButtonAPI/PlagueButtonAPI.csproj.user 31 | /PlagueButtonAPI/.vs/PlagueButtonAPI 32 | -------------------------------------------------------------------------------- /Docs/README.md: -------------------------------------------------------------------------------- 1 | # See The Example Mod's Code For A Quick Example Of Usage: [Click Here](https://github.com/PlagueVRC/PlagueButtonAPI/blob/new-ui/PlagueButtonAPI/ExampleButtonAPIUsage/ExampleButtonAPIUsageMain.cs#L60) 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Use-Only License 2 | 3 | Copyright (c) 2021 Plague 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to use and/or distribute copies of the Software, and to permit persons to whom the Software is 7 | furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all 10 | copies or substantial portions of the Software. 11 | 12 | The software you develop must fall within non-malicious terms. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | -------------------------------------------------------------------------------- /PlagueButtonAPI/ExampleButtonAPIUsage/ExampleButtonAPIUsage.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | VRChat Mods Folder 6 | AnyCPU 7 | {4090D6AD-C19F-4E2A-9F7B-17128113E139} 8 | Library 9 | Properties 10 | ExampleButtonAPIUsage 11 | ExampleButtonAPIUsage 12 | v4.7.2 13 | 512 14 | true 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | TRACE 22 | prompt 23 | 4 24 | 25 | 26 | true 27 | full 28 | false 29 | G:\Games\SteamLibrary\steamapps\common\VRChat\Mods\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | ..\..\References\ExampleButtonAPIUsage\Assembly-CSharp.dll 37 | False 38 | 39 | 40 | ..\..\References\ExampleButtonAPIUsage\Assembly-CSharp-firstpass.dll 41 | False 42 | 43 | 44 | ..\..\References\ExampleButtonAPIUsage\DataModel.dll 45 | False 46 | 47 | 48 | ..\..\References\ExampleButtonAPIUsage\Il2Cppmscorlib.dll 49 | False 50 | 51 | 52 | ..\..\References\ExampleButtonAPIUsage\Il2CppSystem.dll 53 | False 54 | 55 | 56 | ..\..\References\ExampleButtonAPIUsage\Il2CppSystem.Core.dll 57 | False 58 | 59 | 60 | ..\..\References\ExampleButtonAPIUsage\MelonLoader.dll 61 | False 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | False 73 | ..\..\References\ExampleButtonAPIUsage\UIExpansionKit.dll 74 | False 75 | 76 | 77 | ..\..\References\ExampleButtonAPIUsage\UnhollowerBaseLib.dll 78 | False 79 | 80 | 81 | ..\..\References\ExampleButtonAPIUsage\UnhollowerRuntimeLib.dll 82 | False 83 | 84 | 85 | ..\..\References\ExampleButtonAPIUsage\Unity.TextMeshPro.dll 86 | False 87 | 88 | 89 | ..\..\References\ExampleButtonAPIUsage\UnityEngine.dll 90 | False 91 | 92 | 93 | ..\..\References\ExampleButtonAPIUsage\UnityEngine.AssetBundleModule.dll 94 | False 95 | 96 | 97 | ..\..\References\ExampleButtonAPIUsage\UnityEngine.CoreModule.dll 98 | False 99 | 100 | 101 | ..\..\References\ExampleButtonAPIUsage\UnityEngine.Il2CppImageConversionManager.dll 102 | False 103 | 104 | 105 | ..\..\References\ExampleButtonAPIUsage\UnityEngine.InputLegacyModule.dll 106 | False 107 | 108 | 109 | ..\..\References\ExampleButtonAPIUsage\UnityEngine.TextRenderingModule.dll 110 | False 111 | 112 | 113 | ..\..\References\ExampleButtonAPIUsage\UnityEngine.UI.dll 114 | False 115 | 116 | 117 | ..\..\References\ExampleButtonAPIUsage\UnityEngine.UIElementsModule.dll 118 | False 119 | 120 | 121 | ..\..\References\ExampleButtonAPIUsage\UnityEngine.UIModule.dll 122 | False 123 | 124 | 125 | ..\..\References\ExampleButtonAPIUsage\VRC.UI.Core.dll 126 | False 127 | 128 | 129 | ..\..\References\ExampleButtonAPIUsage\VRC.UI.Elements.dll 130 | False 131 | 132 | 133 | ..\..\References\ExampleButtonAPIUsage\VRC.UI.Shared.dll 134 | False 135 | 136 | 137 | ..\..\References\ExampleButtonAPIUsage\VRCCore-Editor.dll 138 | False 139 | 140 | 141 | ..\..\References\ExampleButtonAPIUsage\VRCCore-Standalone.dll 142 | False 143 | 144 | 145 | False 146 | ..\..\References\ExampleButtonAPIUsage\VRChatUtilityKit.dll 147 | False 148 | 149 | 150 | ..\..\References\ExampleButtonAPIUsage\VRCSDK2.dll 151 | False 152 | 153 | 154 | ..\..\References\ExampleButtonAPIUsage\VRCSDK3A.dll 155 | False 156 | 157 | 158 | ..\..\References\ExampleButtonAPIUsage\VRCSDKBase.dll 159 | False 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | {1067ac86-8417-4f30-a9d0-ee8027bfb134} 170 | PlagueButtonAPI 171 | False 172 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /PlagueButtonAPI/ExampleButtonAPIUsage/ExampleButtonAPIUsageMain.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Reflection; 5 | using ExampleButtonAPIUsage; 6 | using HarmonyLib; 7 | using MelonLoader; 8 | using PlagueButtonAPI; 9 | using PlagueButtonAPI.Controls; 10 | using PlagueButtonAPI.Controls.Grouping; 11 | using PlagueButtonAPI.Main; 12 | using PlagueButtonAPI.Misc; 13 | using PlagueButtonAPI.Pages; 14 | using UnityEngine; 15 | using VRC; 16 | using VRC.Core; 17 | using VRChatUtilityKit.Ui; 18 | using VRChatUtilityKit.Utilities; 19 | 20 | [assembly: MelonInfo(typeof(ExampleButtonAPIUsageMain), "Example PlagueButtonAPI Usage", "1.0", "Plague")] 21 | [assembly: MelonGame("VRChat", "VRChat")] 22 | 23 | namespace ExampleButtonAPIUsage 24 | { 25 | public class ExampleButtonAPIUsageMain : MelonMod 26 | { 27 | private bool DoPlayerListRefresh = false; 28 | 29 | private Dictionary UserImages = new Dictionary(); 30 | 31 | public override void OnApplicationStart() 32 | { 33 | try 34 | { 35 | ButtonImage = (Environment.CurrentDirectory + "\\ImageToLoad.png").LoadSpriteFromDisk(); 36 | } 37 | catch {} 38 | 39 | NetworkEvents.OnAvatarInstantiated += NetworkEvents_OnAvatarInstantiated; 40 | 41 | HarmonyInstance.Patch(typeof(PortalInternal).GetMethod(nameof(PortalInternal.ConfigurePortal), AccessTools.all), new HarmonyMethod(typeof(ExampleButtonAPIUsageMain).GetMethod(nameof(ConfigurePortal), BindingFlags.NonPublic | BindingFlags.Static))); 42 | } 43 | 44 | private static bool ConfigurePortal(ref string __0, ref string __1, ref int __2, ref Player __3) 45 | { 46 | return __3 == Player.prop_Player_0 || !DisablePortals; 47 | } 48 | 49 | private void NetworkEvents_OnAvatarInstantiated(VRCAvatarManager arg1, ApiAvatar arg2, GameObject arg3) 50 | { 51 | var tex = Utils.TakePictureOfPlayer(arg1.field_Private_VRCPlayer_0); 52 | 53 | var sprite = PlagueButtonAPI.Misc.Utils.CreateSpriteFromTex(tex); 54 | 55 | UserImages[arg1.field_Private_VRCPlayer_0.gameObject.GetOrAddComponent().field_Private_APIUser_0.id] = sprite; 56 | 57 | DoPlayerListRefresh = true; 58 | } 59 | 60 | public override void OnSceneWasLoaded(int buildIndex, string sceneName) 61 | { 62 | if (sceneName == "ui") // If VRC UI Init 63 | { 64 | ButtonAPI.OnInit += () => // Assign, This Will Happen BEFORE QuickMenu Init, ButtonAPI Will Call OnInit On QuickMenu Init. - This is assigning to an event; eventname += delegatehere 65 | { 66 | var Combi = MenuPage.CreatePage(WingSingleButton.Wing.Left, ButtonImage, "TestMenu_1", "Main Menu"); 67 | 68 | var Page = Combi.Item1; 69 | 70 | var FunctionalGroup = Page.AddButtonGroup("Functional Options"); 71 | 72 | FunctionalGroup.AddToggleButton("Disable Portals", "Disables Portals Entirely", "Re-Enables Portals", val => { DisablePortals = val; }).SetToggleState(false, true); 73 | 74 | var NonFunctionalGroup = Page.AddCollapsibleButtonGroup("Non-Functional Options"); 75 | 76 | var PlayerListMenu = NonFunctionalGroup.AddSubMenu(ButtonImage, "PlayersList_1", "Player List"); 77 | 78 | var PlayersGroup = PlayerListMenu.Item1.AddButtonGroup("", true, TextAnchor.UpperLeft); 79 | var Handler = PlayersGroup.gameObject.GetOrAddComponent(); 80 | 81 | Handler.OnUpdateEachSecond += (obj, IsEnabled) => 82 | { 83 | if (IsEnabled && DoPlayerListRefresh) 84 | { 85 | PlayersGroup.gameObject.transform.DestroyChildren(); 86 | 87 | foreach (var player in PlagueButtonAPI.Misc.Utils.GetAllPlayers()) 88 | { 89 | var image = UserImages.ContainsKey(player.field_Private_APIUser_0.id) ? UserImages[player.field_Private_APIUser_0.id] : null; 90 | 91 | if (player?.field_Private_APIUser_0 == null || image == null) 92 | { 93 | MelonLogger.Error("Null Player Or Image!"); 94 | continue; 95 | } 96 | 97 | PlayersGroup.AddSingleButton(player.field_Private_APIUser_0.displayName, "Selects This Player", () => { UiManager.OpenUserInQuickMenu(player.field_Private_APIUser_0); }, true, image); 98 | } 99 | 100 | DoPlayerListRefresh = false; 101 | } 102 | }; 103 | 104 | NonFunctionalGroup.AddSimpleSingleButton("Show Alerts", "Simple Button", () => 105 | { 106 | ButtonAPI.GetQuickMenuInstance().ShowAlert("Alert Test"); 107 | 108 | ButtonAPI.GetQuickMenuInstance().ShowOKDialog("Title", "Message", () => 109 | { 110 | MelonLogger.Msg("Okay Clicked! Showing Yes/No Popup.."); 111 | 112 | MelonCoroutines.Start(RunMe()); 113 | 114 | IEnumerator RunMe() 115 | { 116 | yield return new WaitForSeconds(3f); 117 | 118 | ButtonAPI.GetQuickMenuInstance().ShowConfirmDialog("Title", "Message", () => { MelonLogger.Msg("Yes Clicked!"); }, () => { MelonLogger.Msg("No Clicked!"); }); 119 | 120 | yield break; 121 | } 122 | }); 123 | }); 124 | 125 | NonFunctionalGroup.AddToggleButton("Toggle", "Toggle On", "Toggle Off", val => { MelonLogger.Msg("Toggle Button Clicked! -> State: " + val); }).SetToggleState(true, true); 126 | 127 | NonFunctionalGroup.AddSlider("Slider", "Slider", val => { MelonLogger.Msg("Slider Adjusted! -> State: " + val); }); 128 | 129 | Page.AddSlider("Slider", "Slider", val => { MelonLogger.Msg("Slider Adjusted! -> State: " + val); }); 130 | 131 | var Dropdown = Page.AddCollapsibleButtonGroup("Dropdown"); 132 | 133 | Dropdown.AddSingleButton("KB", "KB", () => 134 | { 135 | var Pos = ButtonAPI.GetEyeCamera().transform.position + ButtonAPI.GetEyeCamera().transform.forward * 1f; 136 | 137 | CustomInputPickup.Spawn(Pos, ButtonAPI.GetEyeCamera().transform.LookAtThisWithoutRef(Pos), s => 138 | { 139 | MelonLogger.Warning($"Text Confirmed: {s}"); 140 | }); 141 | }, false, ButtonImage); 142 | 143 | Dropdown.AddLabel("Label", "Label", () => { MelonLogger.Msg("Label Clicked!"); }); 144 | 145 | Page.AddLabel("Thanks For Looking. :)", null); 146 | 147 | // Constructor Is Needed For Raw Transforms For Now 148 | var UserGroup = new CollapsibleButtonGroup(TransformHelper.SelectedUser_Local, "Example User Options"); 149 | 150 | UserGroup.AddSingleButton("Button", "Button", () => 151 | { 152 | var SelectedPlayer = PlagueButtonAPI.Misc.Utils.GetCurrentlySelectedPlayer(); 153 | 154 | MelonLogger.Msg("Button Clicked! - Selected Player: " + (SelectedPlayer != null ? SelectedPlayer.field_Private_APIUser_0.displayName : "")); 155 | }); 156 | }; 157 | } 158 | } 159 | 160 | #region Variables 161 | 162 | internal static bool DisablePortals = false; 163 | internal static Sprite ButtonImage = null; 164 | 165 | #endregion 166 | } 167 | } -------------------------------------------------------------------------------- /PlagueButtonAPI/ExampleButtonAPIUsage/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ExampleButtonAPIUsage")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ExampleButtonAPIUsage")] 13 | [assembly: AssemblyCopyright("Copyright © 2021")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("4090d6ad-c19f-4e2a-9f7b-17128113e139")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /PlagueButtonAPI/ExampleButtonAPIUsage/Utils.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using UnityEngine; 4 | using VRC; 5 | using VRC.UI.Elements.Menus; 6 | using PlagueButtonAPI.Misc; 7 | 8 | namespace ExampleButtonAPIUsage 9 | { 10 | internal class Utils 11 | { 12 | private static GameObject AvatarPicTaker; 13 | internal static Texture2D TakePictureOfPlayer(VRCPlayer player) 14 | { 15 | var avatar = player.transform.Find("ForwardDirection/Avatar").gameObject; 16 | var manager = player.prop_VRCAvatarManager_0; 17 | 18 | var OldLayer = player == VRCPlayer.field_Internal_Static_VRCPlayer_0 19 | ? (1 << LayerMask.NameToLayer("PlayerLocal")) 20 | : (1 << LayerMask.NameToLayer("Player")); 21 | 22 | var layer = new System.Random().Next(0, 9999); 23 | 24 | avatar.layer = layer; 25 | 26 | if (AvatarPicTaker == null) 27 | { 28 | AvatarPicTaker = new GameObject("AvatarPicTaker"); 29 | } 30 | 31 | AvatarPicTaker.SetActive(false); 32 | 33 | var CamComp = AvatarPicTaker.GetOrAddComponent(); 34 | 35 | CamComp.clearFlags = CameraClearFlags.SolidColor; 36 | CamComp.backgroundColor = new Color(0f, 0f, 0f, 0f); 37 | 38 | /* Enable camera */ 39 | AvatarPicTaker.SetActive(true); 40 | 41 | /* Move camera infront of head */ 42 | var descriptor = (manager.prop_VRCAvatarDescriptor_0 ?? manager.prop_VRC_AvatarDescriptor_1 ?? manager.prop_VRC_AvatarDescriptor_0); 43 | var head_height = descriptor.ViewPosition.y; 44 | var head = avatar.transform.position + new Vector3(0, head_height, 0); 45 | var target = head + avatar.transform.forward * 0.3f; 46 | var camera = CamComp; 47 | 48 | camera.useOcclusionCulling = false; 49 | camera.farClipPlane = 0.6f; 50 | camera.nearClipPlane = 0.05f; 51 | camera.transform.position = target; 52 | camera.transform.LookAt(head); 53 | 54 | camera.cullingMask = layer; 55 | camera.orthographic = true; 56 | camera.orthographicSize = head_height / 8; 57 | 58 | if (camera.targetTexture == null) 59 | { 60 | camera.targetTexture = new RenderTexture(256, 256, 0); 61 | } 62 | 63 | var currentRT = RenderTexture.active; 64 | RenderTexture.active = camera.targetTexture; 65 | 66 | camera.Render(); 67 | 68 | var image = new Texture2D(camera.targetTexture.width, camera.targetTexture.height, 69 | TextureFormat.RGBA32, false, true) 70 | { name = $"{player.field_Private_ApiAvatar_0.id}" }; 71 | image.ReadPixels(new Rect(0, 0, camera.targetTexture.width, camera.targetTexture.height), 0, 0); 72 | image.Apply(); 73 | image.hideFlags = HideFlags.DontUnloadUnusedAsset; 74 | 75 | RenderTexture.active = currentRT; 76 | 77 | AvatarPicTaker.SetActive(false); 78 | 79 | avatar.layer = OldLayer; 80 | 81 | return image; 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /PlagueButtonAPI/PlagueButtonAPI.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.852 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlagueButtonAPI", "PlagueButtonAPI\PlagueButtonAPI.csproj", "{1067AC86-8417-4F30-A9D0-EE8027BFB134}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExampleButtonAPIUsage", "ExampleButtonAPIUsage\ExampleButtonAPIUsage.csproj", "{4090D6AD-C19F-4E2A-9F7B-17128113E139}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Normal|Any CPU = Normal|Any CPU 13 | VRChat Mods Folder|Any CPU = VRChat Mods Folder|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {1067AC86-8417-4F30-A9D0-EE8027BFB134}.Normal|Any CPU.ActiveCfg = Normal|Any CPU 17 | {1067AC86-8417-4F30-A9D0-EE8027BFB134}.Normal|Any CPU.Build.0 = Normal|Any CPU 18 | {1067AC86-8417-4F30-A9D0-EE8027BFB134}.VRChat Mods Folder|Any CPU.ActiveCfg = VRChat Mods Folder|Any CPU 19 | {1067AC86-8417-4F30-A9D0-EE8027BFB134}.VRChat Mods Folder|Any CPU.Build.0 = VRChat Mods Folder|Any CPU 20 | {4090D6AD-C19F-4E2A-9F7B-17128113E139}.Normal|Any CPU.ActiveCfg = Normal|Any CPU 21 | {4090D6AD-C19F-4E2A-9F7B-17128113E139}.Normal|Any CPU.Build.0 = Normal|Any CPU 22 | {4090D6AD-C19F-4E2A-9F7B-17128113E139}.VRChat Mods Folder|Any CPU.ActiveCfg = VRChat Mods Folder|Any CPU 23 | {4090D6AD-C19F-4E2A-9F7B-17128113E139}.VRChat Mods Folder|Any CPU.Build.0 = VRChat Mods Folder|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {56B333B1-7344-486F-8B4B-65B7696DD4DF} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /PlagueButtonAPI/PlagueButtonAPI/Controls/Base Classes/Button.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using UnityEngine; 7 | using UnityEngine.UI; 8 | 9 | namespace PlagueButtonAPI.Controls.Base_Classes 10 | { 11 | public class Button : ControlWithText 12 | { 13 | public Image subMenuIcon => transform?.Find("Badge_MMJump")?.GetComponentInChildren(true) ?? transform?.Find("Container/Icon_Arrow")?.GetComponentInChildren(true); 14 | 15 | public Image buttonImage => transform?.Find("Icon")?.GetComponentInChildren(true) ?? transform?.Find("Container/Icon")?.GetComponentInChildren(true); 16 | 17 | public UnityEngine.UI.Button button => gameObject?.GetComponentInChildren(true); 18 | 19 | public VRC.UI.Elements.Tooltips.UiTooltip tooltip => gameObject?.GetComponentsInChildren(true).FirstOrDefault(o => !string.IsNullOrEmpty(o.field_Public_String_0) || !string.IsNullOrEmpty(o.field_Public_String_1)); 20 | 21 | public void SetAction(Action newAction) 22 | { 23 | button.onClick = new UnityEngine.UI.Button.ButtonClickedEvent(); 24 | button.onClick.AddListener(newAction); 25 | } 26 | 27 | public void SetInteractable(bool val) 28 | { 29 | button.interactable = val; 30 | } 31 | 32 | public void SetIcon(Sprite newIcon, bool preserveColor = false) 33 | { 34 | if (newIcon == null) 35 | { 36 | buttonImage.gameObject.SetActive(false); 37 | return; 38 | } 39 | buttonImage.sprite = newIcon; 40 | buttonImage.overrideSprite = newIcon; 41 | buttonImage.gameObject.SetActive(true); 42 | if (preserveColor) 43 | { 44 | buttonImage.color = Color.white; 45 | } 46 | } 47 | 48 | public void SetIconColor(Color color) 49 | { 50 | buttonImage.color = color; 51 | } 52 | 53 | public void SetTooltip(string newTooltip) 54 | { 55 | if (tooltip == null) 56 | { 57 | return; 58 | } 59 | 60 | tooltip.field_Public_String_0 = newTooltip; 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /PlagueButtonAPI/PlagueButtonAPI/Controls/Base Classes/ControlWithText.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using UnityEngine; 7 | using UnityEngine.UI; 8 | 9 | namespace PlagueButtonAPI.Controls.Base_Classes 10 | { 11 | public class ControlWithText : GenericControl 12 | { 13 | public Image buttonBackground => transform?.Find("Background")?.GetComponentInChildren(true) ?? transform?.Find("Container/Background")?.GetComponentInChildren(true); 14 | 15 | public TMPro.TextMeshProUGUI text => gameObject?.GetComponentInChildren(true); 16 | 17 | [Obsolete] 18 | public TMPro.TextMeshProUGUI buttonText => text; 19 | 20 | public void SetText(string newText) 21 | { 22 | text.text = newText; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /PlagueButtonAPI/PlagueButtonAPI/Controls/Base Classes/GenericControl.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using UnityEngine; 7 | 8 | namespace PlagueButtonAPI.Controls.Base_Classes 9 | { 10 | public class GenericControl 11 | { 12 | public GameObject gameObject; 13 | 14 | public bool IsNull => gameObject == null; 15 | 16 | public bool active => gameObject?.active ?? false; 17 | 18 | public bool activeSelf => gameObject?.activeSelf ?? false; 19 | 20 | public Transform transform => gameObject?.transform; 21 | 22 | public void SetActive(bool state) 23 | { 24 | gameObject?.SetActive(state); 25 | } 26 | 27 | public void Destroy() 28 | { 29 | UnityEngine.Object.Destroy(gameObject); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /PlagueButtonAPI/PlagueButtonAPI/Controls/Base Classes/Toggle.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using MelonLoader; 8 | using UnhollowerRuntimeLib.XrefScans; 9 | using UnityEngine; 10 | using UnityEngine.UI; 11 | using VRC.UI.Elements.Controls; 12 | using VRC.UI.Elements.Tooltips; 13 | 14 | namespace PlagueButtonAPI.Controls.Base_Classes 15 | { 16 | public class Toggle : ControlWithText 17 | { 18 | public UnityEngine.UI.Toggle toggle => gameObject?.GetComponentInChildren(true); 19 | 20 | [Obsolete] 21 | public UnityEngine.UI.Toggle buttontoggle => toggle; 22 | 23 | public UiToggleTooltip tooltip => gameObject?.GetComponentInChildren(true); 24 | 25 | public Image OnImage => transform?.Find("Icon_On")?.GetComponentInChildren(true); 26 | public Image OffImage => transform?.Find("Icon_Off")?.GetComponentInChildren(true); 27 | 28 | public bool? ToggleState => toggle?.isOn; 29 | 30 | internal bool NextState = false; 31 | 32 | public void SetAction(Action newAction) 33 | { 34 | toggle.onValueChanged = new UnityEngine.UI.Toggle.ToggleEvent(); 35 | toggle.onValueChanged.AddListener((Action)delegate (bool val) 36 | { 37 | newAction?.Invoke(val); 38 | }); 39 | } 40 | 41 | public void SetInteractable(bool val) 42 | { 43 | toggle.interactable = val; 44 | } 45 | 46 | internal bool AllowUserInvoke = true; 47 | 48 | public void SetToggleState(bool newState, bool invoke = false) 49 | { 50 | NextState = newState; 51 | 52 | if (gameObject.active) 53 | { 54 | AllowUserInvoke = false; 55 | 56 | toggle.isOn = newState; 57 | 58 | AllowUserInvoke = true; 59 | 60 | if (tooltip != null) 61 | { 62 | tooltip.field_Private_Boolean_1 = !newState; 63 | } 64 | } 65 | 66 | if (invoke) 67 | { 68 | toggle.onValueChanged.Invoke(newState); 69 | } 70 | } 71 | 72 | internal bool ToolTipOne = false; 73 | public void SetTooltip(string newOffTooltip, string newOnTooltip) 74 | { 75 | if (!ToolTipOne) 76 | { 77 | tooltip.field_Public_String_0 = newOnTooltip; 78 | tooltip.field_Public_String_1 = newOffTooltip; 79 | } 80 | else 81 | { 82 | tooltip.field_Public_String_0 = newOffTooltip; 83 | tooltip.field_Public_String_1 = newOnTooltip; 84 | } 85 | } 86 | 87 | public void SetOnIcon(Sprite newIcon) 88 | { 89 | if (newIcon == null) 90 | { 91 | OnImage.gameObject.SetActive(false); 92 | return; 93 | } 94 | 95 | OnImage.sprite = newIcon; 96 | OnImage.overrideSprite = newIcon; 97 | OnImage.gameObject.SetActive(true); 98 | } 99 | 100 | public void SetOffIcon(Sprite newIcon) 101 | { 102 | if (newIcon == null) 103 | { 104 | OffImage.gameObject.SetActive(false); 105 | return; 106 | } 107 | 108 | OffImage.sprite = newIcon; 109 | OffImage.overrideSprite = newIcon; 110 | OffImage.gameObject.SetActive(true); 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /PlagueButtonAPI/PlagueButtonAPI/Controls/Buttons/Label.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using MelonLoader; 4 | using PlagueButtonAPI.Controls.Grouping; 5 | using PlagueButtonAPI.Misc; 6 | using PlagueButtonAPI.Pages; 7 | using UnityEngine; 8 | using UnityEngine.UI; 9 | using VRC.UI.Core.Styles; 10 | 11 | namespace PlagueButtonAPI.Controls 12 | { 13 | public class Label 14 | { 15 | public readonly SimpleSingleButton LabelButton; 16 | 17 | public Label(Transform parent, string text, string tooltip, Action onClick = null) 18 | { 19 | LabelButton = new SimpleSingleButton(parent, text, tooltip, onClick); 20 | 21 | LabelButton.buttonBackground.color = new Color(0f, 0f, 0f, 0f); 22 | 23 | var Handler = LabelButton.gameObject.AddComponent(); 24 | 25 | Handler.OnUpdateEachSecond += (a, b) => 26 | { 27 | LabelButton.text.transform.localPosition = new Vector3(0f, -19f, 0f); 28 | }; 29 | 30 | if (onClick == null) 31 | { 32 | LabelButton.gameObject.GetOrAddComponent