├── .github └── workflows │ ├── build-listing.yml │ └── release.yml ├── .gitignore ├── Docs └── VRCSdkSettings ├── LICENSE ├── Packages ├── befuddledlabs.linuxvrchatsdkpatch.avatars │ ├── package.json │ └── package.json.meta ├── befuddledlabs.linuxvrchatsdkpatch.base │ ├── Editor.meta │ ├── Editor │ │ ├── 0Harmony.dll │ │ ├── 0Harmony.dll.meta │ │ ├── Base.cs │ │ ├── Base.cs.meta │ │ ├── CannyPopup.cs │ │ ├── CannyPopup.cs.meta │ │ ├── LinuxVRChatSDKPatch-Base.Editor.asmdef │ │ ├── LinuxVRChatSDKPatch-Base.Editor.asmdef.meta │ │ ├── Patch.cs │ │ ├── Patch.cs.meta │ │ ├── UI.cs │ │ └── UI.cs.meta │ ├── package.json │ └── package.json.meta └── befuddledlabs.linuxvrchatsdkpatch.worlds │ ├── Editor.meta │ ├── Editor │ ├── LinuxVRChatSDKPatch-Worlds.Editor.asmdef │ ├── LinuxVRChatSDKPatch-Worlds.Editor.asmdef.meta │ ├── Patch.cs │ ├── Patch.cs.meta │ ├── World.cs │ └── World.cs.meta │ ├── package.json │ └── package.json.meta ├── README.md ├── Website ├── app.js ├── banner.png ├── favicon.ico ├── index.html └── styles.css └── source.json /.github/workflows/build-listing.yml: -------------------------------------------------------------------------------- 1 | name: Build Repo Listing 2 | # https://github.com/vrchat-community/template-package/blob/main/.github/workflows/build-listing.yml 3 | 4 | env: 5 | listPublishDirectory: Website 6 | pathToCi: ci 7 | 8 | on: 9 | workflow_dispatch: 10 | workflow_run: 11 | workflows: [Build Release] 12 | types: 13 | - completed 14 | release: 15 | types: [published, created, edited, unpublished, deleted, released] 16 | 17 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 18 | permissions: 19 | contents: read 20 | pages: write 21 | id-token: write 22 | 23 | # Allow one concurrent deployment 24 | concurrency: 25 | group: "pages" 26 | cancel-in-progress: true 27 | 28 | jobs: 29 | 30 | # Build the VPM Listing Website and deploy to GitHub Pages 31 | build-listing: 32 | name: build-listing 33 | environment: 34 | name: github-pages 35 | url: ${{ steps.deployment.outputs.page_url }} 36 | runs-on: ubuntu-latest 37 | steps: 38 | 39 | # Checkout Local Repository 40 | - name: Checkout Local Repository 41 | uses: actions/checkout@v4 42 | 43 | # Checkout Automation Repository without removing prior checkouts 44 | - name: Checkout Automation Repository 45 | uses: actions/checkout@v4 46 | with: 47 | repository: vrchat-community/package-list-action 48 | path: ${{ env.pathToCi }} 49 | clean: false 50 | 51 | # Load cached data from previous runs 52 | - name: Restore Cache 53 | uses: actions/cache@v4 54 | with: 55 | path: | 56 | ${{ env.pathToCi }}/.nuke/temp 57 | ~/.nuget/packages 58 | key: ${{ runner.os }}-${{ hashFiles('**/global.json', '**/*.csproj') }} 59 | 60 | # Build Package Version Listing with Nuke 61 | - name: Build Package Version Listing 62 | run: ${{ env.pathToCi }}/build.cmd BuildMultiPackageListing --root ${{ env.pathToCi }} --list-publish-directory $GITHUB_WORKSPACE/${{ env.listPublishDirectory }} 63 | env: 64 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 65 | 66 | # Prepare for GitHub Pages deployment 67 | - name: Setup Pages 68 | uses: actions/configure-pages@v5 69 | 70 | # Upload the VPM Listing Website to GitHub Pages artifacts 71 | - name: Upload Pages Artifact 72 | uses: actions/upload-pages-artifact@v3 73 | with: 74 | path: ${{ env.listPublishDirectory }} 75 | 76 | # Deploy the uploaded VPM Listing Website to GitHub Pages 77 | - name: Deploy to GitHub Pages 78 | id: deployment 79 | uses: actions/deploy-pages@v4 80 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Build Release 2 | # https://github.com/vrchat-community/template-package/blob/main/.github/workflows/release.yml 3 | 4 | on: 5 | workflow_dispatch: 6 | 7 | jobs: 8 | 9 | # Validate Repository Configuration 10 | config: 11 | runs-on: ubuntu-latest 12 | outputs: 13 | config_package: ${{ steps.config_package.outputs.configPackage }} 14 | steps: 15 | 16 | # Ensure that required repository variable has been created for the Package 17 | - name: Validate Package Config 18 | id: config_package 19 | run: | 20 | echo "configPackage=true" >> $GITHUB_OUTPUT; 21 | 22 | # Build and release the Package 23 | # If the repository is not configured properly, this job will be skipped 24 | build: 25 | needs: config 26 | runs-on: ubuntu-latest 27 | permissions: 28 | contents: write 29 | if: needs.config.outputs.config_package == 'true' 30 | steps: 31 | 32 | # Checkout Local Repository 33 | - name: Checkout 34 | uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac 35 | with: 36 | lfs: "true" 37 | 38 | # Get the Package version based on the package.json file 39 | - name: Get Version 40 | id: version 41 | uses: zoexx/github-action-json-file-properties@b9f36ce6ee6fe2680cd3c32b2c62e22eade7e590 42 | with: 43 | file_path: "Packages/befuddledlabs.linuxvrchatsdkpatch.base/package.json" 44 | prop_path: "version" 45 | 46 | # Configure the Environment Variables needed for releasing the Package 47 | - name: Set Environment Variables 48 | run: | 49 | echo "baseZipFile=befuddledlabs.linuxvrchatsdkpatch.base-${{ steps.version.outputs.value }}".zip >> $GITHUB_ENV 50 | echo "baseUnityPackage=befuddledlabs.linuxvrchatsdkpatch.base-${{ steps.version.outputs.value }}.unitypackage" >> $GITHUB_ENV 51 | echo "version=${{ steps.version.outputs.value }}" >> $GITHUB_ENV 52 | 53 | # Zip the Package for release 54 | - name: Create Package Zip 55 | working-directory: "Packages/befuddledlabs.linuxvrchatsdkpatch.base" 56 | run: zip -r "${{ github.workspace }}/${{ env.baseZipFile }}" . 57 | 58 | # Build a list of .meta files for future use 59 | - name: Track Package Meta Files 60 | run: find "Packages/befuddledlabs.linuxvrchatsdkpatch.base/" -name \*.meta >> metaListBase 61 | 62 | # Make a UnityPackage version of the Package for release 63 | - name: Create UnityPackage 64 | uses: pCYSl5EDgo/create-unitypackage@cfcd3cf0391a5ef1306342794866a9897c32af0b 65 | with: 66 | package-path: ${{ env.baseUnityPackage }} 67 | include-files: metaListBase 68 | 69 | 70 | 71 | # Configure the Environment Variables needed for releasing the Package 72 | - name: Set Environment Variables 73 | run: | 74 | echo "avatarsZipFile=befuddledlabs.linuxvrchatsdkpatch.avatars-${{ steps.version.outputs.value }}".zip >> $GITHUB_ENV 75 | echo "avatarsUnityPackage=befuddledlabs.linuxvrchatsdkpatch.avatars-${{ steps.version.outputs.value }}.unitypackage" >> $GITHUB_ENV 76 | echo "version=${{ steps.version.outputs.value }}" >> $GITHUB_ENV 77 | 78 | # Zip the Package for release 79 | - name: Create Package Zip 80 | working-directory: "Packages/befuddledlabs.linuxvrchatsdkpatch.avatars" 81 | run: zip -r "${{ github.workspace }}/${{ env.avatarsZipFile }}" . 82 | 83 | # Build a list of .meta files for future use 84 | - name: Track Package Meta Files 85 | run: find "Packages/befuddledlabs.linuxvrchatsdkpatch.avatars/" -name \*.meta >> metaListAvatars 86 | 87 | # Make a UnityPackage version of the Package for release 88 | - name: Create UnityPackage 89 | uses: pCYSl5EDgo/create-unitypackage@cfcd3cf0391a5ef1306342794866a9897c32af0b 90 | with: 91 | package-path: ${{ env.avatarsUnityPackage }} 92 | include-files: metaListAvatars 93 | 94 | 95 | 96 | # Configure the Environment Variables needed for releasing the Package 97 | - name: Set Environment Variables 98 | run: | 99 | echo "worldsZipFile=befuddledlabs.linuxvrchatsdkpatch.worlds-${{ steps.version.outputs.value }}".zip >> $GITHUB_ENV 100 | echo "worldsUnityPackage=befuddledlabs.linuxvrchatsdkpatch.worlds-${{ steps.version.outputs.value }}.unitypackage" >> $GITHUB_ENV 101 | echo "version=${{ steps.version.outputs.value }}" >> $GITHUB_ENV 102 | 103 | # Zip the Package for release 104 | - name: Create Package Zip 105 | working-directory: "Packages/befuddledlabs.linuxvrchatsdkpatch.worlds" 106 | run: zip -r "${{ github.workspace }}/${{ env.worldsZipFile }}" . 107 | 108 | # Build a list of .meta files for future use 109 | - name: Track Package Meta Files 110 | run: find "Packages/befuddledlabs.linuxvrchatsdkpatch.worlds/" -name \*.meta >> metaListWorlds 111 | 112 | # Make a UnityPackage version of the Package for release 113 | - name: Create UnityPackage 114 | uses: pCYSl5EDgo/create-unitypackage@cfcd3cf0391a5ef1306342794866a9897c32af0b 115 | with: 116 | package-path: ${{ env.worldsUnityPackage }} 117 | include-files: metaListWorlds 118 | 119 | 120 | 121 | 122 | # Make a release tag of the version from the package.json file 123 | - name: Create Tag 124 | id: tag_version_base 125 | uses: rickstaa/action-create-tag@88dbf7ff6fe2405f8e8f6c6fdfd78829bc631f83 126 | with: 127 | tag: "${{ env.version }}-base" 128 | 129 | # Publish the Release to GitHub 130 | - name: Make Release Base 131 | uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 132 | with: 133 | files: | 134 | ${{ env.baseZipFile }} 135 | ${{ env.baseUnityPackage }} 136 | Packages/befuddledlabs.linuxvrchatsdkpatch.base/package.json 137 | tag_name: ${{ env.version }}-base 138 | 139 | # Make a release tag of the version from the package.json file 140 | - name: Create Tag 141 | id: tag_version_avatars 142 | uses: rickstaa/action-create-tag@88dbf7ff6fe2405f8e8f6c6fdfd78829bc631f83 143 | with: 144 | tag: "${{ env.version }}-avatars" 145 | 146 | - name: Make Release World 147 | uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 148 | with: 149 | files: | 150 | ${{ env.avatarsZipFile }} 151 | ${{ env.avatarsUnityPackage }} 152 | Packages/befuddledlabs.linuxvrchatsdkpatch.avatars/package.json 153 | tag_name: ${{ env.version }}-avatars 154 | 155 | # Make a release tag of the version from the package.json file 156 | - name: Create Tag 157 | id: tag_version_worlds 158 | uses: rickstaa/action-create-tag@88dbf7ff6fe2405f8e8f6c6fdfd78829bc631f83 159 | with: 160 | tag: "${{ env.version }}-worlds" 161 | 162 | - name: Make Release World 163 | uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 164 | with: 165 | files: | 166 | ${{ env.worldsZipFile }} 167 | ${{ env.worldsUnityPackage }} 168 | Packages/befuddledlabs.linuxvrchatsdkpatch.worlds/package.json 169 | tag_name: ${{ env.version }}-worlds 170 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # This .gitignore file should be placed at the root of your Unity project directory 2 | # 3 | # Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore 4 | # 5 | /[Ll]ibrary/ 6 | /[Tt]emp/ 7 | /[Oo]bj/ 8 | /[Bb]uild/ 9 | /[Bb]uilds/ 10 | /[Ll]ogs/ 11 | /[Mm]emoryCaptures/ 12 | 13 | # Asset meta data should only be ignored when the corresponding asset is also ignored 14 | !/[Aa]ssets/**/*.meta 15 | 16 | # Uncomment this line if you wish to ignore the asset store tools plugin 17 | # /[Aa]ssets/AssetStoreTools* 18 | 19 | # Autogenerated Jetbrains Rider plugin 20 | [Aa]ssets/Plugins/Editor/JetBrains* 21 | 22 | # Visual Studio cache directory 23 | .vs/ 24 | 25 | # Gradle cache directory 26 | .gradle/ 27 | 28 | # Autogenerated VS/MD/Consulo solution and project files 29 | ExportedObj/ 30 | .consulo/ 31 | *.csproj 32 | *.unityproj 33 | *.sln 34 | *.suo 35 | *.tmp 36 | *.user 37 | *.userprefs 38 | *.pidb 39 | *.booproj 40 | *.svd 41 | *.pdb 42 | *.mdb 43 | *.opendb 44 | *.VC.db 45 | 46 | # Unity3D generated meta files 47 | *.pidb.meta 48 | *.pdb.meta 49 | *.mdb.meta 50 | 51 | # Unity3D generated file on crash reports 52 | sysinfo.txt 53 | 54 | # Builds 55 | *.apk 56 | *.unitypackage 57 | 58 | # Crashlytics generated file 59 | crashlytics-build.properties 60 | 61 | .idea/.idea.vpm-package-maker/.idea 62 | Assets/PackageMakerWindowData.asset* 63 | .idea 64 | .vscode 65 | Packages/befuddledlabs.opensyncdance/Binaries 66 | Packages/befuddledlabs.opensyncdance/Binaries.meta 67 | -------------------------------------------------------------------------------- /Docs/VRCSdkSettings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BefuddledLabs/LinuxVRChatSDKPatch/89911a8246fa346a25f7ec1242cf215f9a659595/Docs/VRCSdkSettings -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 BefuddledLabs 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 deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Packages/befuddledlabs.linuxvrchatsdkpatch.avatars/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "befuddledlabs.linuxvrchatsdkpatch-avatars", 3 | "displayName": "Linux VRChat SDK Patch Avatars", 4 | "version": "0.2.0", 5 | "url": "https://github.com/BefuddledLabs/LinuxVRChatSDKPatch", 6 | "author": { 7 | "name": "BefuddledLabs" 8 | }, 9 | "unity": "2022.3", 10 | "description": "Patches the VRChat SDK to work properly on linux.", 11 | "vpmDependencies": { 12 | "com.vrchat.avatars": "^3.8.2", 13 | "befuddledlabs.linuxvrchatsdkpatch-base": "0.2.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Packages/befuddledlabs.linuxvrchatsdkpatch.avatars/package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 532ad6517a9518c87a7ec037d2d109ce 3 | PackageManifestImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Packages/befuddledlabs.linuxvrchatsdkpatch.base/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 58ce5c1f94965d53bb4bad29228fe8bc 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Packages/befuddledlabs.linuxvrchatsdkpatch.base/Editor/0Harmony.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BefuddledLabs/LinuxVRChatSDKPatch/89911a8246fa346a25f7ec1242cf215f9a659595/Packages/befuddledlabs.linuxvrchatsdkpatch.base/Editor/0Harmony.dll -------------------------------------------------------------------------------- /Packages/befuddledlabs.linuxvrchatsdkpatch.base/Editor/0Harmony.dll.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6455a5762a87e7816be1f10f0135f22b 3 | PluginImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | iconMap: {} 7 | executionOrder: {} 8 | defineConstraints: [] 9 | isPreloaded: 0 10 | isOverridable: 1 11 | isExplicitlyReferenced: 0 12 | validateReferences: 1 13 | platformData: 14 | - first: 15 | Any: 16 | second: 17 | enabled: 0 18 | settings: {} 19 | - first: 20 | Editor: Editor 21 | second: 22 | enabled: 1 23 | settings: 24 | DefaultValueInitialized: true 25 | - first: 26 | Windows Store Apps: WindowsStoreApps 27 | second: 28 | enabled: 0 29 | settings: 30 | CPU: AnyCPU 31 | userData: 32 | assetBundleName: 33 | assetBundleVariant: 34 | -------------------------------------------------------------------------------- /Packages/befuddledlabs.linuxvrchatsdkpatch.base/Editor/Base.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using HarmonyLib; 4 | using JetBrains.Annotations; 5 | using UnityEditor; 6 | using VRC.Core; 7 | using VRC.SDKBase.Editor; 8 | 9 | namespace BefuddledLabs.LinuxVRChatSdkPatch.Base.Editor 10 | { 11 | [HarmonyPatch] 12 | public static class Base 13 | { 14 | [CanBeNull] 15 | public static string GetCompatDataPath() 16 | { 17 | var vrChatPath = SDKClientUtilities.GetSavedVRCInstallPath(); 18 | if (string.IsNullOrWhiteSpace(vrChatPath)) 19 | return null; 20 | 21 | var dir = new FileInfo(vrChatPath).Directory; 22 | if (dir == null) 23 | return null; 24 | 25 | while (!dir.Name.Contains("steamapps", StringComparison.OrdinalIgnoreCase)) 26 | { 27 | dir = dir.Parent; 28 | if (dir == null) 29 | return null; 30 | } 31 | 32 | return dir.FullName + "/compatdata/"; 33 | } 34 | 35 | [CanBeNull] 36 | public static string GetVrcCompatDataPath() 37 | { 38 | return GetCompatDataPath() + "438100/"; 39 | } 40 | 41 | public static string GetSavedProtonPath() 42 | { 43 | var savedVrcInstallPath = ""; 44 | if (EditorPrefs.HasKey("LinuxVRC_protonPath")) 45 | savedVrcInstallPath = EditorPrefs.GetString("LinuxVRC_protonPath"); 46 | return savedVrcInstallPath; 47 | } 48 | 49 | public static void SetProtonPath(string protonPath) 50 | { 51 | EditorPrefs.SetString("LinuxVRC_protonPath", protonPath); 52 | } 53 | 54 | // Thanks Bartkk <3 55 | [HarmonyPrefix] 56 | [HarmonyPatch(typeof(VRC_SdkBuilder), "GetLocalLowPath")] 57 | public static bool GetLocalLowPathPrefix(ref string __result) 58 | { 59 | __result = GetVrcCompatDataPath() + "pfx/drive_c/users/steamuser/AppData/LocalLow/"; 60 | return false; 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /Packages/befuddledlabs.linuxvrchatsdkpatch.base/Editor/Base.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b8760caffaad5340fbc6af250ae76cee 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Packages/befuddledlabs.linuxvrchatsdkpatch.base/Editor/CannyPopup.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using UnityEditor; 3 | using UnityEngine; 4 | 5 | namespace BefuddledLabs.LinuxVRChatSdkPatch.Base.Editor 6 | { 7 | [InitializeOnLoad] 8 | public static class CannyPopup 9 | { 10 | [MenuItem("VRChat SDK/Utilities/Linux/Clear LinuxVRC_cannyDialog")] 11 | public static void ResetLinuxVRC_cannyDialog() => EditorPrefs.SetBool("LinuxVRC_cannyDialog", false); 12 | 13 | static CannyPopup() 14 | { 15 | if (EditorPrefs.GetBool("LinuxVRC_cannyDialog", false) || !RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) 16 | return; 17 | 18 | var result = EditorUtility.DisplayDialog("Linux VRChat Patch", 19 | "Please upvote this canny instead of needing this patch local tests.", 20 | "Open Canny", "Don't show again"); 21 | 22 | if (result) 23 | Application.OpenURL("https://feedback.vrchat.com/sdk-bug-reports/p/add-proton-support-to-the-sdk-for-local-tests"); 24 | EditorPrefs.SetBool("LinuxVRC_cannyDialog", true);// 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Packages/befuddledlabs.linuxvrchatsdkpatch.base/Editor/CannyPopup.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9dd49f9cb3f1d33448c0e6c95c7cea27 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Packages/befuddledlabs.linuxvrchatsdkpatch.base/Editor/LinuxVRChatSDKPatch-Base.Editor.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "LinuxVRChatSdkPatch.Base.Editor", 3 | "rootNamespace": "", 4 | "references": [ 5 | "VRC.SDKBase", 6 | "VRC.SDKBase.Editor" 7 | ], 8 | "includePlatforms": [ 9 | "Editor" 10 | ], 11 | "excludePlatforms": [], 12 | "allowUnsafeCode": false, 13 | "overrideReferences": false, 14 | "precompiledReferences": [], 15 | "autoReferenced": true, 16 | "defineConstraints": [], 17 | "versionDefines": [], 18 | "noEngineReferences": false 19 | } 20 | -------------------------------------------------------------------------------- /Packages/befuddledlabs.linuxvrchatsdkpatch.base/Editor/LinuxVRChatSDKPatch-Base.Editor.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a330f0ccedb2dc0af8ef51b369f732f9 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Packages/befuddledlabs.linuxvrchatsdkpatch.base/Editor/Patch.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using HarmonyLib; 3 | using UnityEditor; 4 | 5 | namespace BefuddledLabs.LinuxVRChatSdkPatch.Base.Editor 6 | { 7 | [InitializeOnLoad] 8 | public static class Patch 9 | { 10 | internal static Harmony _harmony; 11 | 12 | 13 | static Patch() 14 | { 15 | if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) 16 | return; 17 | 18 | _harmony = new Harmony("BefuddledLabs.LinuxVRChatSdkPatch-World"); 19 | _harmony.PatchAll(); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /Packages/befuddledlabs.linuxvrchatsdkpatch.base/Editor/Patch.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 78c1807470a80d74cb170fa4b2bb4781 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Packages/befuddledlabs.linuxvrchatsdkpatch.base/Editor/UI.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Reflection.Emit; 4 | using HarmonyLib; 5 | using UnityEditor; 6 | using UnityEngine; 7 | 8 | namespace BefuddledLabs.LinuxVRChatSdkPatch.Base.Editor 9 | { 10 | [HarmonyPatch] 11 | public static class UI 12 | { 13 | private static void OnProtonInstallPathGUI() 14 | { 15 | var protonPath = Base.GetSavedProtonPath(); 16 | EditorGUILayout.LabelField("Proton", EditorStyles.boldLabel); 17 | EditorGUILayout.LabelField("Proton Python File: ", protonPath); 18 | EditorGUILayout.BeginHorizontal(); 19 | GUILayout.Label(""); 20 | 21 | if (GUILayout.Button("Edit")) 22 | { 23 | var initPath = ""; 24 | if (!string.IsNullOrEmpty(protonPath)) 25 | initPath = protonPath; 26 | 27 | protonPath = EditorUtility.OpenFilePanel("Choose Proton Python File (not wine in the proton folder)", initPath, ""); 28 | Base.SetProtonPath(protonPath); 29 | } 30 | 31 | EditorGUILayout.EndHorizontal(); 32 | EditorGUILayout.Separator(); 33 | } 34 | 35 | [HarmonyTranspiler] 36 | [HarmonyPatch(typeof(VRCSdkControlPanel), "ShowSettings")] 37 | public static IEnumerable ShowSettingsTranspiler(IEnumerable instructions) 38 | { 39 | var codes = instructions.ToList(); 40 | for (var i = 0; i < codes.Count; i++) 41 | { 42 | if (codes[i].opcode != OpCodes.Call) continue; 43 | if (!codes[i].operand.ToString().Contains("OnVRCInstallPathGUI")) continue; 44 | codes.Insert(i, CodeInstruction.Call(typeof(UI), nameof(OnProtonInstallPathGUI))); 45 | break; 46 | } 47 | 48 | return codes.AsEnumerable(); 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /Packages/befuddledlabs.linuxvrchatsdkpatch.base/Editor/UI.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: dbfa77e6c282bae3ab7fbccbd5142079 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Packages/befuddledlabs.linuxvrchatsdkpatch.base/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "befuddledlabs.linuxvrchatsdkpatch-base", 3 | "displayName": "Linux VRChat SDK Patch Base", 4 | "version": "0.2.0", 5 | "url": "https://github.com/BefuddledLabs/LinuxVRChatSDKPatch", 6 | "author": { 7 | "name": "BefuddledLabs" 8 | }, 9 | "unity": "2022.3", 10 | "description": "Patches the VRChat SDK to work properly on linux.", 11 | "vpmDependencies": { 12 | "com.vrchat.base": "^3.8.2" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Packages/befuddledlabs.linuxvrchatsdkpatch.base/package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f7d4179ed8e7d43e9993bde7a4a4d62c 3 | PackageManifestImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Packages/befuddledlabs.linuxvrchatsdkpatch.worlds/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cc9e5f06d3ce1f5219a519fd6d6b18fa 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Packages/befuddledlabs.linuxvrchatsdkpatch.worlds/Editor/LinuxVRChatSDKPatch-Worlds.Editor.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "LinuxVRChatSdkPatch.Worlds.Editor", 3 | "rootNamespace": "", 4 | "references": [ 5 | "VRC.SDKBase", 6 | "VRC.SDKBase.Editor", 7 | "LinuxVRChatSdkPatch.Base.Editor" 8 | ], 9 | "includePlatforms": [ 10 | "Editor" 11 | ], 12 | "excludePlatforms": [], 13 | "allowUnsafeCode": false, 14 | "overrideReferences": false, 15 | "precompiledReferences": [], 16 | "autoReferenced": true, 17 | "defineConstraints": [], 18 | "versionDefines": [], 19 | "noEngineReferences": false 20 | } 21 | -------------------------------------------------------------------------------- /Packages/befuddledlabs.linuxvrchatsdkpatch.worlds/Editor/LinuxVRChatSDKPatch-Worlds.Editor.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bc2f97d5950098db29ed6066b0edc397 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Packages/befuddledlabs.linuxvrchatsdkpatch.worlds/Editor/Patch.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using HarmonyLib; 3 | using UnityEditor; 4 | 5 | namespace BefuddledLabs.LinuxVRChatSdkPatch.Worlds.Editor 6 | { 7 | [InitializeOnLoad] 8 | public static class Patch 9 | { 10 | internal static Harmony _harmony; 11 | 12 | 13 | static Patch() 14 | { 15 | if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) 16 | return; 17 | 18 | _harmony = new Harmony("BefuddledLabs.LinuxVRChatSdkPatch-World"); 19 | _harmony.PatchAll(); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Packages/befuddledlabs.linuxvrchatsdkpatch.worlds/Editor/Patch.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a8762508aa493fb6586ff78f98e04f3c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Packages/befuddledlabs.linuxvrchatsdkpatch.worlds/Editor/World.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.Text; 5 | using System.Text.RegularExpressions; 6 | using System.Threading; 7 | using HarmonyLib; 8 | using UnityEngine.Networking; 9 | using VRC.Core; 10 | using VRC.SDK3.Editor.Builder; 11 | using VRC.SDKBase.Editor; 12 | using Debug = UnityEngine.Debug; 13 | 14 | namespace BefuddledLabs.LinuxVRChatSdkPatch.Worlds.Editor 15 | { 16 | [HarmonyPatch] 17 | public static class World 18 | { 19 | [HarmonyPrefix] 20 | [HarmonyPatch(typeof(VRCWorldAssetExporter), "RunWorldTestDesktop", typeof(string))] 21 | public static bool RunWorldTestDesktopPrefix(object[] __args) 22 | { 23 | var vrcInstallPath = SDKClientUtilities.GetSavedVRCInstallPath(); 24 | if (string.IsNullOrEmpty(vrcInstallPath) || !File.Exists(vrcInstallPath)) 25 | { 26 | Debug.LogError("couldn't get VRChat path.. You probobly forgot to set it at: " + 27 | "VRChat control panel > Settings > VRChat Client"); 28 | return true; 29 | } 30 | 31 | var protonInstallPath = Base.Editor.Base.GetSavedProtonPath(); 32 | if (string.IsNullOrEmpty(protonInstallPath) || !File.Exists(protonInstallPath)) 33 | { 34 | Debug.LogError("couldn't get Proton path.. You probobly forgot to set it at: " + 35 | "VRChat control panel > Settings > Proton Python File"); 36 | return true; 37 | } 38 | 39 | var compatDataPath = Base.Editor.Base.GetVrcCompatDataPath(); 40 | if (compatDataPath == null) // Check if we could find the compatdata directory 41 | { 42 | Debug.LogError("Could not find compatdata Path"); 43 | return false; 44 | } 45 | 46 | // Making sure that the paths are using forward slashes 47 | var bundleFilePath = ((string)__args[0]).Replace('\\', '/'); 48 | 49 | bundleFilePath = UnityWebRequest.EscapeURL(bundleFilePath).Replace("+", "%20"); 50 | 51 | var args = new StringBuilder(); 52 | args.Append("run "); 53 | args.Append(vrcInstallPath); 54 | args.Append(' '); 55 | 56 | args.Append("--url=create?roomId="); 57 | args.Append(VRC.Tools.GetRandomDigits(10)); // Random roomId 58 | args.Append("&hidden=true"); 59 | args.Append("&name=BuildAndRun"); 60 | args.Append("&url=file:///"); 61 | args.Append(bundleFilePath); 62 | 63 | args.Append(" --enable-debug-gui"); 64 | args.Append(" --enable-sdk-log-levels"); 65 | args.Append(" --enable-udon-debug-logging"); 66 | if (VRCSettings.ForceNoVR) 67 | args.Append(" --no-vr"); 68 | if (VRCSettings.WatchWorlds) 69 | args.Append(" --watch-worlds"); 70 | 71 | 72 | var argsPathFixed = Regex.Replace(args.ToString(), @"file:[/\\]*", "file:///Z:/"); // The file we have is relative to / and not the "c drive" Z:/ is / 73 | 74 | Debug.Log(protonInstallPath + argsPathFixed); 75 | 76 | var processStartInfo = 77 | new ProcessStartInfo(protonInstallPath, argsPathFixed) 78 | { 79 | EnvironmentVariables = 80 | { 81 | { "STEAM_COMPAT_DATA_PATH", compatDataPath }, 82 | { "STEAM_COMPAT_CLIENT_INSTALL_PATH", Environment.GetEnvironmentVariable("HOME") + "/.steam/" } 83 | }, 84 | WorkingDirectory = Path.GetDirectoryName(vrcInstallPath) ?? "", 85 | UseShellExecute = false 86 | }; 87 | for (var index = 0; index < VRCSettings.NumClients; ++index) 88 | { 89 | Process.Start(processStartInfo); 90 | Thread.Sleep(3000); 91 | } 92 | 93 | return false; 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /Packages/befuddledlabs.linuxvrchatsdkpatch.worlds/Editor/World.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7e10b8a03b410d91d85b8da3c171bb74 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Packages/befuddledlabs.linuxvrchatsdkpatch.worlds/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "befuddledlabs.linuxvrchatsdkpatch-worlds", 3 | "displayName": "Linux VRChat SDK Patch Worlds", 4 | "version": "0.2.0", 5 | "url": "https://github.com/BefuddledLabs/LinuxVRChatSDKPatch", 6 | "author": { 7 | "name": "BefuddledLabs" 8 | }, 9 | "unity": "2022.3", 10 | "description": "Patches the VRChat SDK to work properly on linux.", 11 | "vpmDependencies": { 12 | "com.vrchat.worlds": "^3.8.2", 13 | "befuddledlabs.linuxvrchatsdkpatch-base": "0.2.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Packages/befuddledlabs.linuxvrchatsdkpatch.worlds/package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 532ad6517a9518c87a7ec037d2d109ce 3 | PackageManifestImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Linux VRChat SDK Patch 2 | 3 | > [!WARNING] 4 | > This modifies the VRChat SDK using [Harmony](https://github.com/pardeike/Harmony) to properly work on Linux. \ 5 | > This is directly against the VRChat Terms of Service. 6 | 7 | ## How to install 8 | 1. [ALCOM](https://github.com/vrc-get/vrc-get) [Recommended] 9 | 1. Add the `Linux VRChat SDK Patch` package to [ALCOM](https://github.com/vrc-get/vrc-get) via the listing at [`befuddledlabs.github.io/LinuxVRChatSDKPatch`](https://befuddledlabs.github.io/LinuxVRChatSDKPatch/). 10 | 2. Install the appropriate package `Linux VRChat SDK Patch` Worlds or Avatars 11 | 2. Manual 12 | 1. Download the Base and either Worlds or Avatars UnityPackage(s) from the [Releases](https://github.com/BefuddledLabs/LinuxVRChatSDKPatch/releases). 13 | 14 | ## How to use 15 | ![VRCSdkSettings](/Docs/VRCSdkSettings) 16 | 17 | Select both your VRChat exe and proton binary in the settings of the VRChat SDK's settings pannel. 18 | 19 | ## Development 20 | 21 | To make modifications to this package: 22 | 23 | 1. Clone this repository to a non-unity project folder. 24 | 2. Create a symbolic link from the package(s) into a Unity project's package folder. 25 | 3. The package should be editable via Unity and any external editor. 26 | 27 | ## Acknowledgements 28 | - [*Bartkk*](https://github.com/Bartkk0) 29 | - For making the original [VRCSDKonLinux](https://github.com/Bartkk0/VRCSDKonLinux). 30 | - And sharing their latest patches they hadn't gotten around to releasing. 31 | -------------------------------------------------------------------------------- /Website/app.js: -------------------------------------------------------------------------------- 1 | import { baseLayerLuminance, StandardLuminance } from 'https://unpkg.com/@fluentui/web-components'; 2 | 3 | const LISTING_URL = "{{ listingInfo.Url }}"; 4 | 5 | const PACKAGES = { 6 | {{~ for package in packages ~}} 7 | "{{ package.Name }}": { 8 | name: "{{ package.Name }}", 9 | displayName: "{{ if package.DisplayName; package.DisplayName; end; }}", 10 | description: "{{ if package.Description; package.Description; end; }}", 11 | version: "{{ package.Version }}", 12 | author: { 13 | name: "{{ if package.Author.Name; package.Author.Name; end; }}", 14 | url: "{{ if package.Author.Url; package.Author.Url; end; }}", 15 | }, 16 | dependencies: { 17 | {{~ for dependency in package.Dependencies ~}} 18 | "{{ dependency.Name }}": "{{ dependency.Version }}", 19 | {{~ end ~}} 20 | }, 21 | keywords: [ 22 | {{~ for keyword in package.Keywords ~}} 23 | "{{ keyword }}", 24 | {{~ end ~}} 25 | ], 26 | license: "{{ package.License }}", 27 | licensesUrl: "{{ package.LicensesUrl }}", 28 | }, 29 | {{~ end ~}} 30 | }; 31 | 32 | const setTheme = () => { 33 | const isDarkTheme = () => window.matchMedia("(prefers-color-scheme: dark)").matches; 34 | if (isDarkTheme()) { 35 | baseLayerLuminance.setValueFor(document.documentElement, StandardLuminance.DarkMode); 36 | } else { 37 | baseLayerLuminance.setValueFor(document.documentElement, StandardLuminance.LightMode); 38 | } 39 | } 40 | 41 | (() => { 42 | setTheme(); 43 | 44 | window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => { 45 | setTheme(); 46 | }); 47 | 48 | const packageGrid = document.getElementById('packageGrid'); 49 | 50 | const searchInput = document.getElementById('searchInput'); 51 | searchInput.addEventListener('input', ({ target: { value = '' }}) => { 52 | const items = packageGrid.querySelectorAll('fluent-data-grid-row[row-type="default"]'); 53 | items.forEach(item => { 54 | if (value === '') { 55 | item.style.display = 'grid'; 56 | return; 57 | } 58 | if ( 59 | item.dataset?.packageName?.toLowerCase()?.includes(value.toLowerCase()) || 60 | item.dataset?.packageId?.toLowerCase()?.includes(value.toLowerCase()) 61 | ) { 62 | item.style.display = 'grid'; 63 | } else { 64 | item.style.display = 'none'; 65 | } 66 | }); 67 | }); 68 | 69 | const urlBarHelpButton = document.getElementById('urlBarHelp'); 70 | const addListingToVccHelp = document.getElementById('addListingToVccHelp'); 71 | urlBarHelpButton.addEventListener('click', () => { 72 | addListingToVccHelp.hidden = false; 73 | }); 74 | const addListingToVccHelpClose = document.getElementById('addListingToVccHelpClose'); 75 | addListingToVccHelpClose.addEventListener('click', () => { 76 | addListingToVccHelp.hidden = true; 77 | }); 78 | 79 | const vccListingInfoUrlFieldCopy = document.getElementById('vccListingInfoUrlFieldCopy'); 80 | vccListingInfoUrlFieldCopy.addEventListener('click', () => { 81 | const vccUrlField = document.getElementById('vccListingInfoUrlField'); 82 | vccUrlField.select(); 83 | navigator.clipboard.writeText(vccUrlField.value); 84 | vccUrlFieldCopy.appearance = 'accent'; 85 | setTimeout(() => { 86 | vccUrlFieldCopy.appearance = 'neutral'; 87 | }, 1000); 88 | }); 89 | 90 | const vccAddRepoButton = document.getElementById('vccAddRepoButton'); 91 | vccAddRepoButton.addEventListener('click', () => window.location.assign(`vcc://vpm/addRepo?url=${encodeURIComponent(LISTING_URL)}`)); 92 | 93 | const vccUrlFieldCopy = document.getElementById('vccUrlFieldCopy'); 94 | vccUrlFieldCopy.addEventListener('click', () => { 95 | const vccUrlField = document.getElementById('vccUrlField'); 96 | vccUrlField.select(); 97 | navigator.clipboard.writeText(vccUrlField.value); 98 | vccUrlFieldCopy.appearance = 'accent'; 99 | setTimeout(() => { 100 | vccUrlFieldCopy.appearance = 'neutral'; 101 | }, 1000); 102 | }); 103 | 104 | const rowMoreMenu = document.getElementById('rowMoreMenu'); 105 | const hideRowMoreMenu = e => { 106 | if (rowMoreMenu.contains(e.target)) return; 107 | document.removeEventListener('click', hideRowMoreMenu); 108 | rowMoreMenu.hidden = true; 109 | } 110 | 111 | const rowMenuButtons = document.querySelectorAll('.rowMenuButton'); 112 | rowMenuButtons.forEach(button => { 113 | button.addEventListener('click', e => { 114 | if (rowMoreMenu?.hidden) { 115 | rowMoreMenu.style.top = `${e.clientY + e.target.clientHeight}px`; 116 | rowMoreMenu.style.left = `${e.clientX - 120}px`; 117 | rowMoreMenu.hidden = false; 118 | 119 | const downloadLink = rowMoreMenu.querySelector('#rowMoreMenuDownload'); 120 | const downloadListener = () => { 121 | window.open(e?.target?.dataset?.packageUrl, '_blank'); 122 | } 123 | downloadLink.addEventListener('change', () => { 124 | downloadListener(); 125 | downloadLink.removeEventListener('change', downloadListener); 126 | }); 127 | 128 | setTimeout(() => { 129 | document.addEventListener('click', hideRowMoreMenu); 130 | }, 1); 131 | } 132 | }); 133 | }); 134 | 135 | const packageInfoModal = document.getElementById('packageInfoModal'); 136 | const packageInfoModalClose = document.getElementById('packageInfoModalClose'); 137 | packageInfoModalClose.addEventListener('click', () => { 138 | packageInfoModal.hidden = true; 139 | }); 140 | 141 | // Fluent dialogs use nested shadow-rooted elements, so we need to use JS to style them 142 | const modalControl = packageInfoModal.shadowRoot.querySelector('.control'); 143 | modalControl.style.maxHeight = "90%"; 144 | modalControl.style.transition = 'height 0.2s ease-in-out'; 145 | modalControl.style.overflowY = 'hidden'; 146 | 147 | const packageInfoName = document.getElementById('packageInfoName'); 148 | const packageInfoId = document.getElementById('packageInfoId'); 149 | const packageInfoVersion = document.getElementById('packageInfoVersion'); 150 | const packageInfoDescription = document.getElementById('packageInfoDescription'); 151 | const packageInfoAuthor = document.getElementById('packageInfoAuthor'); 152 | const packageInfoDependencies = document.getElementById('packageInfoDependencies'); 153 | const packageInfoKeywords = document.getElementById('packageInfoKeywords'); 154 | const packageInfoLicense = document.getElementById('packageInfoLicense'); 155 | 156 | const rowAddToVccButtons = document.querySelectorAll('.rowAddToVccButton'); 157 | rowAddToVccButtons.forEach((button) => { 158 | button.addEventListener('click', () => window.location.assign(`vcc://vpm/addRepo?url=${encodeURIComponent(LISTING_URL)}`)); 159 | }); 160 | 161 | const rowPackageInfoButton = document.querySelectorAll('.rowPackageInfoButton'); 162 | rowPackageInfoButton.forEach((button) => { 163 | button.addEventListener('click', e => { 164 | const packageId = e.target.dataset?.packageId; 165 | const packageInfo = PACKAGES?.[packageId]; 166 | if (!packageInfo) { 167 | console.error(`Did not find package ${packageId}. Packages available:`, PACKAGES); 168 | return; 169 | } 170 | 171 | packageInfoName.textContent = packageInfo.displayName; 172 | packageInfoId.textContent = packageId; 173 | packageInfoVersion.textContent = `v${packageInfo.version}`; 174 | packageInfoDescription.textContent = packageInfo.description; 175 | packageInfoAuthor.textContent = packageInfo.author.name; 176 | packageInfoAuthor.href = packageInfo.author.url; 177 | 178 | if ((packageInfo.keywords?.length ?? 0) === 0) { 179 | packageInfoKeywords.parentElement.classList.add('hidden'); 180 | } else { 181 | packageInfoKeywords.parentElement.classList.remove('hidden'); 182 | packageInfoKeywords.innerHTML = null; 183 | packageInfo.keywords.forEach(keyword => { 184 | const keywordDiv = document.createElement('div'); 185 | keywordDiv.classList.add('me-2', 'mb-2', 'badge'); 186 | keywordDiv.textContent = keyword; 187 | packageInfoKeywords.appendChild(keywordDiv); 188 | }); 189 | } 190 | 191 | if (!packageInfo.license?.length && !packageInfo.licensesUrl?.length) { 192 | packageInfoLicense.parentElement.classList.add('hidden'); 193 | } else { 194 | packageInfoLicense.parentElement.classList.remove('hidden'); 195 | packageInfoLicense.textContent = packageInfo.license ?? 'See License'; 196 | packageInfoLicense.href = packageInfo.licensesUrl ?? '#'; 197 | } 198 | 199 | packageInfoDependencies.innerHTML = null; 200 | Object.entries(packageInfo.dependencies).forEach(([name, version]) => { 201 | const depRow = document.createElement('li'); 202 | depRow.classList.add('mb-2'); 203 | depRow.textContent = `${name} @ v${version}`; 204 | packageInfoDependencies.appendChild(depRow); 205 | }); 206 | 207 | packageInfoModal.hidden = false; 208 | 209 | setTimeout(() => { 210 | const height = packageInfoModal.querySelector('.col').clientHeight; 211 | modalControl.style.setProperty('--dialog-height', `${height + 14}px`); 212 | }, 1); 213 | }); 214 | }); 215 | 216 | const packageInfoVccUrlFieldCopy = document.getElementById('packageInfoVccUrlFieldCopy'); 217 | packageInfoVccUrlFieldCopy.addEventListener('click', () => { 218 | const vccUrlField = document.getElementById('packageInfoVccUrlField'); 219 | vccUrlField.select(); 220 | navigator.clipboard.writeText(vccUrlField.value); 221 | vccUrlFieldCopy.appearance = 'accent'; 222 | setTimeout(() => { 223 | vccUrlFieldCopy.appearance = 'neutral'; 224 | }, 1000); 225 | }); 226 | 227 | const packageInfoListingHelp = document.getElementById('packageInfoListingHelp'); 228 | packageInfoListingHelp.addEventListener('click', () => { 229 | addListingToVccHelp.hidden = false; 230 | }); 231 | })(); -------------------------------------------------------------------------------- /Website/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BefuddledLabs/LinuxVRChatSDKPatch/89911a8246fa346a25f7ec1242cf215f9a659595/Website/banner.png -------------------------------------------------------------------------------- /Website/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BefuddledLabs/LinuxVRChatSDKPatch/89911a8246fa346a25f7ec1242cf215f9a659595/Website/favicon.ico -------------------------------------------------------------------------------- /Website/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | VCC Listing 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 | {{~ if listingInfo.BannerImage; ~}} 15 |
16 | {{~ end; ~}} 17 |

18 | {{~ listingInfo.Name ~}} 19 |

20 | {{~ if listingInfo.Description; ~}} 21 |
{{ listingInfo.Description }}
22 | {{~ end; ~}} 23 |
24 | {{~ if listingInfo.Author.Email; ~}} 25 | 26 | {{ listingInfo.Author.Email }} 27 | 28 | {{~ end; ~}} 29 | 30 | {{~ if listingInfo.InfoLink.Url ~}} 31 | 34 |
35 | ⚠️These packages modify the VRChat SDK, This is directly against the VRChat TOS. 36 |
37 | {{~ end; ~}} 38 |
39 |
40 |
41 | 42 | 43 | Add to VCC 44 | 45 | 46 | 47 | 48 | Copy 49 | 50 | 51 | How to add a listing to your VCC 52 | 53 | 54 | 55 | 56 | 57 | 58 |
59 | 100 |
101 | 102 |
103 | 113 | 175 | 176 | 177 | 178 | 179 | Name 180 | 181 | 182 | Type 183 | 184 | 185 | 186 | 187 | {{~ for package in packages ~}} 188 | 189 | 190 |
191 |
{{ package.DisplayName }}
192 |
{{ package.Description }}
193 |
{{ package.Name }}
194 |
195 |
196 | 197 | {{ package.Type }} 198 | 199 | 200 | Add to VCC 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 |
213 | {{~ end ~}} 214 |
215 |
216 | {{~ if listingInfo.InfoLink.Url ~}} 217 | 220 | {{~ end; ~}} 221 |
222 | 223 | 224 | 225 | -------------------------------------------------------------------------------- /Website/styles.css: -------------------------------------------------------------------------------- 1 | :root { 2 | color-scheme: light dark; 3 | } 4 | 5 | * { 6 | box-sizing: border-box; 7 | } 8 | 9 | body { 10 | padding: 0; 11 | margin: 0; 12 | min-width: 100vw; 13 | min-height: 100vh; 14 | display: flex; 15 | align-items: center; 16 | justify-content: center; 17 | font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; 18 | color: var(--neutral-foreground-rest); 19 | } 20 | 21 | .hidden { 22 | display: none !important; 23 | } 24 | 25 | .row { 26 | display: flex; 27 | flex-direction: row; 28 | } 29 | 30 | .col { 31 | display: flex; 32 | flex-direction: column; 33 | } 34 | 35 | .content { 36 | max-width: 1000px; 37 | width: 100%; 38 | margin: 0 auto; 39 | } 40 | 41 | .align-items-center { 42 | align-items: center; 43 | } 44 | 45 | .justify-content-between { 46 | justify-content: space-between; 47 | } 48 | 49 | .justify-content-end { 50 | justify-content: flex-end; 51 | } 52 | 53 | h1 { 54 | margin-bottom: 0.5rem; 55 | } 56 | 57 | .caption1 { 58 | font-size: 1rem; 59 | color: var(--neutral-foreground-hover); 60 | } 61 | 62 | .caption2 { 63 | font-size: 0.8rem; 64 | margin-top: 0.25rem; 65 | color: var(--neutral-foreground-rest); 66 | } 67 | 68 | .packages { 69 | margin: 0.5rem 0 1rem 0; 70 | max-width: 90%; 71 | padding: 0.25rem; 72 | display: flex; 73 | flex: 1; 74 | } 75 | 76 | #packageGrid { 77 | overflow-y: auto; 78 | width: 100%; 79 | max-height: 40rem; 80 | } 81 | 82 | .packages .packageName { 83 | font-size: 1.1rem; 84 | font-weight: 600; 85 | margin: 0.25rem 0; 86 | } 87 | 88 | .searchBlock { 89 | margin-top: 1rem; 90 | width: 100%; 91 | max-width: 90%; 92 | } 93 | 94 | .searchBlock .root { 95 | width: 100%; 96 | } 97 | 98 | #searchInput { 99 | width: 100%; 100 | } 101 | 102 | .vccUrlField { 103 | min-width: 450px; 104 | max-width: 90%; 105 | flex-grow:1; 106 | } 107 | 108 | #addListingToVccHelp { 109 | z-index: 11; 110 | } 111 | 112 | #packageInfoModal { 113 | z-index: 10; 114 | } 115 | 116 | #rowMoreMenu { 117 | top: 0; 118 | left: 0; 119 | position: absolute; 120 | z-index: 10; 121 | } 122 | 123 | #rowMoreMenu a { 124 | display: block; 125 | text-decoration: none; 126 | color: var(--neutral-foreground-rest); 127 | } 128 | 129 | .bannerImage { 130 | aspect-ratio: 5 / 1; 131 | border-radius: 6px; 132 | max-width: 90%; 133 | width: 100%; 134 | background-size: cover; 135 | background-position: center; 136 | background-repeat: no-repeat; 137 | margin-bottom: 0.25rem; 138 | } 139 | 140 | .badge { 141 | border-radius: 4px; 142 | padding: 0.25rem 0.5rem; 143 | background-color: var(--neutral-fill-hover); 144 | } 145 | 146 | .m-0 { 147 | margin: 0; 148 | } 149 | 150 | .m-1 { 151 | margin: 0.25rem; 152 | } 153 | 154 | .m-2 { 155 | margin: 0.5rem; 156 | } 157 | 158 | .m-3 { 159 | margin: 0.75rem; 160 | } 161 | 162 | .m-4 { 163 | margin: 1rem; 164 | } 165 | 166 | .m-5 { 167 | margin: 2rem; 168 | } 169 | 170 | .mt-1 { 171 | margin-top: 0.25rem; 172 | } 173 | 174 | .mt-2 { 175 | margin-top: 0.5rem; 176 | } 177 | 178 | .mt-3 { 179 | margin-top: 0.75rem; 180 | } 181 | 182 | .mt-4 { 183 | margin-top: 1rem; 184 | } 185 | 186 | .mt-5 { 187 | margin-top: 2rem; 188 | } 189 | 190 | .mb-1 { 191 | margin-bottom: 0.25rem; 192 | } 193 | 194 | .mb-2 { 195 | margin-bottom: 0.5rem; 196 | } 197 | 198 | .mb-3 { 199 | margin-bottom: 0.75rem; 200 | } 201 | 202 | .mb-4 { 203 | margin-bottom: 1rem; 204 | } 205 | 206 | .mb-5 { 207 | margin-bottom: 2rem; 208 | } 209 | 210 | .ms-1 { 211 | margin-left: 0.25rem; 212 | } 213 | 214 | .ms-2 { 215 | margin-left: 0.5rem; 216 | } 217 | 218 | .ms-3 { 219 | margin-left: 0.75rem; 220 | } 221 | 222 | .ms-4 { 223 | margin-left: 1rem; 224 | } 225 | 226 | .ms-5 { 227 | margin-left: 2rem; 228 | } 229 | 230 | .me-1 { 231 | margin-right: 0.25rem; 232 | } 233 | 234 | .me-2 { 235 | margin-right: 0.5rem; 236 | } 237 | 238 | .me-3 { 239 | margin-right: 0.75rem; 240 | } 241 | 242 | .me-4 { 243 | margin-right: 1rem; 244 | } 245 | 246 | .me-5 { 247 | margin-right: 2rem; 248 | } 249 | 250 | .p-1 { 251 | padding: 0.25rem; 252 | } 253 | 254 | .p-2 { 255 | padding: 0.5rem; 256 | } 257 | 258 | .p-3 { 259 | padding: 0.75rem; 260 | } 261 | 262 | .p-4 { 263 | padding: 1rem; 264 | } 265 | 266 | .p-5 { 267 | padding: 2rem; 268 | } 269 | 270 | .pt-1 { 271 | padding-top: 0.25rem; 272 | } 273 | 274 | .pt-2 { 275 | padding-top: 0.5rem; 276 | } 277 | 278 | .pt-3 { 279 | padding-top: 0.75rem; 280 | } 281 | 282 | .pt-4 { 283 | padding-top: 1rem; 284 | } 285 | 286 | .pt-5 { 287 | padding-top: 2rem; 288 | } 289 | 290 | .pb-1 { 291 | padding-bottom: 0.25rem; 292 | } 293 | 294 | .pb-2 { 295 | padding-bottom: 0.5rem; 296 | } 297 | 298 | .pb-3 { 299 | padding-bottom: 0.75rem; 300 | } 301 | 302 | .pb-4 { 303 | padding-bottom: 1rem; 304 | } 305 | 306 | .pb-5 { 307 | padding-bottom: 2rem; 308 | } 309 | 310 | .ps-1 { 311 | padding-left: 0.25rem; 312 | } 313 | 314 | .ps-2 { 315 | padding-left: 0.5rem; 316 | } 317 | 318 | .ps-3 { 319 | padding-left: 0.75rem; 320 | } 321 | 322 | .ps-4 { 323 | padding-left: 1rem; 324 | } 325 | 326 | .ps-5 { 327 | padding-left: 2rem; 328 | } 329 | 330 | .pe-1 { 331 | padding-right: 0.25rem; 332 | } 333 | 334 | .pe-2 { 335 | padding-right: 0.5rem; 336 | } 337 | 338 | .pe-3 { 339 | padding-right: 0.75rem; 340 | } 341 | 342 | .pe-4 { 343 | padding-right: 1rem; 344 | } 345 | 346 | .pe-5 { 347 | padding-right: 2rem; 348 | } 349 | 350 | .w-100 { 351 | width: 100%; 352 | } 353 | 354 | .flex-1 { 355 | flex: 1; 356 | } -------------------------------------------------------------------------------- /source.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"Linux VRChat SDK Patch Listing", 3 | "id":"befuddledlabs.linuxvrchatsdkpatch", 4 | "url":"https://befuddledlabs.github.io/LinuxVRChatSDKPatch/index.json", 5 | "author":{ 6 | "name":"BefuddledLabs" 7 | }, 8 | "description":"Listing for some Linux patchs to the VRChat SDK", 9 | "infoLink":{ 10 | "url":"https://befuddledlabs.github.io/LinuxVRChatSDKPatch/", 11 | "text":"View on GitHub" 12 | }, 13 | "bannerUrl":"banner.png", 14 | "githubRepos":[ 15 | "BefuddledLabs/LinuxVRChatSDKPatch" 16 | ] 17 | } 18 | --------------------------------------------------------------------------------