├── .github └── workflows │ └── VRC-Asset-Release-And-Upload.yml ├── .gitignore ├── Instancer.meta ├── Instancer ├── Local-Mirror-Detection Instancer.asmdef ├── Local-Mirror-Detection Instancer.asmdef.meta ├── Local-Mirror-Detection Instancer.cs └── Local-Mirror-Detection Instancer.cs.meta ├── LICENSE ├── LICENSE.meta ├── Media.meta ├── Media ├── Preview.png ├── Web │ ├── Preview.webp │ └── Preview.webp.meta └── setup.mp4 ├── Mirror Detection FX.controller ├── Mirror Detection FX.controller.meta ├── README.md ├── README.md.meta ├── Resources.meta ├── Resources ├── Animations.meta └── Animations │ ├── Mirror Detection Buffer.anim │ ├── Mirror Detection Buffer.anim.meta │ ├── Mirror Detection False.anim │ ├── Mirror Detection False.anim.meta │ ├── Mirror Detection True.anim │ └── Mirror Detection True.anim.meta ├── package.json └── package.json.meta /.github/workflows/VRC-Asset-Release-And-Upload.yml: -------------------------------------------------------------------------------- 1 | name: Create Tag and Release 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | TAG: 6 | required: true 7 | type: string 8 | description: Tag to be applied, for example 1.0.0 9 | CHANGELOG: 10 | required: true 11 | type: string 12 | description: Enter as a list using '- ' and '\n' (e.g. "- First item\n- Second item".). Don't use ". 13 | CHECKOUT_REF: 14 | type: string 15 | description: full commit hash, if none supplied, latest main is taken 16 | 17 | jobs: 18 | deploy: 19 | uses: VRLabs/Workflows-collection/.github/workflows/VRC-Asset-Release-And-Upload.yml@main 20 | with: 21 | ASSETS_PATH: . 22 | TAG: ${{ inputs.TAG }} 23 | CHANGELOG: ${{ inputs.CHANGELOG }} 24 | REPOSITORY: ${{ github.repository }} 25 | CHECKOUT_REF: ${{ inputs.CHECKOUT_REF }} 26 | secrets: inherit -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .github/.DS_Store 2 | .DS_Store 3 | /Media/*.meta 4 | -------------------------------------------------------------------------------- /Instancer.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f78e8bd7aabb79d468d691527da5852f 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Instancer/Local-Mirror-Detection Instancer.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "VRLabs Local-Mirror-Detection Instancer", 3 | "rootNamespace": "", 4 | "references": [], 5 | "includePlatforms": [ 6 | "Editor" 7 | ], 8 | "excludePlatforms": [], 9 | "allowUnsafeCode": false, 10 | "overrideReferences": false, 11 | "precompiledReferences": [], 12 | "autoReferenced": true, 13 | "defineConstraints": [], 14 | "versionDefines": [ 15 | { 16 | "name": "dev.vrlabs.instancer", 17 | "expression": "", 18 | "define": "VRLABS_INSTANCER_FOUND" 19 | } 20 | ], 21 | "noEngineReferences": false 22 | } -------------------------------------------------------------------------------- /Instancer/Local-Mirror-Detection Instancer.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6585e7d475f9a08409880a558b8852d4 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Instancer/Local-Mirror-Detection Instancer.cs: -------------------------------------------------------------------------------- 1 | #if VRLABS_INSTANCER_FOUND 2 | using System; 3 | using System.Linq; 4 | using System.Reflection; 5 | using UnityEditor; 6 | using UnityEngine; 7 | 8 | namespace VRLabs.LocalMirrorDetection 9 | { 10 | public class LocalMirrorDetection : ScriptableObject 11 | { 12 | public const string packageName = "Local-Mirror-Detection"; 13 | 14 | public static string[] excludeRegexs = 15 | { 16 | ".*\\.cs", 17 | ".*\\.asmdef", 18 | "package.json" 19 | }; 20 | 21 | [MenuItem("VRLabs/Create Instance/Local Mirror Detection")] 22 | public static void FancyPackage() 23 | { 24 | Type instancerType = AppDomain.CurrentDomain.GetAssemblies() 25 | .Where(x => x.GetType("VRLabs.Instancer.Instancer") != null) 26 | .Select(x => x.GetType("VRLabs.Instancer.Instancer")).FirstOrDefault(); 27 | 28 | if (instancerType == null) 29 | { 30 | Debug.LogError("Instancer not found. To use this functionality, install the VRLabs Instancer from https://github.com/VRLabs/Instancer"); 31 | return; 32 | } 33 | 34 | MethodInfo instanceMethod = instancerType.GetMethod("Instance", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); 35 | 36 | if (instanceMethod == null) 37 | { 38 | Debug.LogError("Instance method not found"); 39 | return; 40 | } 41 | 42 | var assetPath = new System.Diagnostics.StackTrace(true).GetFrame(0).GetFileName() 43 | .Replace(System.IO.Path.GetDirectoryName(Application.dataPath), "") 44 | .Replace("\\", "/".Replace("./", "")); 45 | 46 | instanceMethod.Invoke(null, new object[] { packageName, assetPath, excludeRegexs }); 47 | } 48 | } 49 | } 50 | #endif -------------------------------------------------------------------------------- /Instancer/Local-Mirror-Detection Instancer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2fe2022bf42df3b458969b96a7ed799d 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 VRLabs LLC 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 | -------------------------------------------------------------------------------- /LICENSE.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f72f042519152482e830f39df9c6f7d8 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Media.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ee1e67a3158d39746942f4e272e2fa37 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Media/Preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VRLabs/Local-Mirror-Detection/093068df74a45c0d3c01245a2f578a271c8dc491/Media/Preview.png -------------------------------------------------------------------------------- /Media/Web/Preview.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VRLabs/Local-Mirror-Detection/093068df74a45c0d3c01245a2f578a271c8dc491/Media/Web/Preview.webp -------------------------------------------------------------------------------- /Media/Web/Preview.webp.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ad6ecf80a4933204096cd16fc83c954f 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Media/setup.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VRLabs/Local-Mirror-Detection/093068df74a45c0d3c01245a2f578a271c8dc491/Media/setup.mp4 -------------------------------------------------------------------------------- /Mirror Detection FX.controller: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1102 &-9049777313585539016 4 | AnimatorState: 5 | serializedVersion: 6 6 | m_ObjectHideFlags: 1 7 | m_CorrespondingSourceObject: {fileID: 0} 8 | m_PrefabInstance: {fileID: 0} 9 | m_PrefabAsset: {fileID: 0} 10 | m_Name: Fork 11 | m_Speed: 1 12 | m_CycleOffset: 0 13 | m_Transitions: 14 | - {fileID: -7715550311558748690} 15 | - {fileID: 3107862120337283806} 16 | m_StateMachineBehaviours: [] 17 | m_Position: {x: 50, y: 50, z: 0} 18 | m_IKOnFeet: 0 19 | m_WriteDefaultValues: 0 20 | m_Mirror: 0 21 | m_SpeedParameterActive: 0 22 | m_MirrorParameterActive: 0 23 | m_CycleOffsetParameterActive: 0 24 | m_TimeParameterActive: 0 25 | m_Motion: {fileID: 7400000, guid: 26ee6725878c84a4ca5ba99b28042ac4, type: 2} 26 | m_Tag: 27 | m_SpeedParameter: 28 | m_MirrorParameter: 29 | m_CycleOffsetParameter: 30 | m_TimeParameter: 31 | --- !u!114 &-7719676013391324315 32 | MonoBehaviour: 33 | m_ObjectHideFlags: 1 34 | m_CorrespondingSourceObject: {fileID: 0} 35 | m_PrefabInstance: {fileID: 0} 36 | m_PrefabAsset: {fileID: 0} 37 | m_GameObject: {fileID: 0} 38 | m_Enabled: 1 39 | m_EditorHideFlags: 0 40 | m_Script: {fileID: -706344726, guid: 67cc4cb7839cd3741b63733d5adf0442, type: 3} 41 | m_Name: 42 | m_EditorClassIdentifier: 43 | parameters: 44 | - type: 0 45 | name: MirrorDetection/DetectMirror 46 | source: 47 | value: 1 48 | valueMin: 0 49 | valueMax: 0 50 | chance: 0 51 | convertRange: 0 52 | sourceMin: 0 53 | sourceMax: 0 54 | destMin: 0 55 | destMax: 0 56 | localOnly: 1 57 | debugString: 58 | --- !u!1101 &-7715550311558748690 59 | AnimatorStateTransition: 60 | m_ObjectHideFlags: 1 61 | m_CorrespondingSourceObject: {fileID: 0} 62 | m_PrefabInstance: {fileID: 0} 63 | m_PrefabAsset: {fileID: 0} 64 | m_Name: 65 | m_Conditions: 66 | - m_ConditionMode: 2 67 | m_ConditionEvent: MirrorDetection/DetectMirror 68 | m_EventTreshold: 0 69 | m_DstStateMachine: {fileID: 0} 70 | m_DstState: {fileID: -2948385516909857121} 71 | m_Solo: 0 72 | m_Mute: 0 73 | m_IsExit: 0 74 | serializedVersion: 3 75 | m_TransitionDuration: 0 76 | m_TransitionOffset: 0 77 | m_ExitTime: 1 78 | m_HasExitTime: 0 79 | m_HasFixedDuration: 0 80 | m_InterruptionSource: 0 81 | m_OrderedInterruption: 1 82 | m_CanTransitionToSelf: 1 83 | --- !u!1102 &-2948385516909857121 84 | AnimatorState: 85 | serializedVersion: 6 86 | m_ObjectHideFlags: 1 87 | m_CorrespondingSourceObject: {fileID: 0} 88 | m_PrefabInstance: {fileID: 0} 89 | m_PrefabAsset: {fileID: 0} 90 | m_Name: Not Mirror 91 | m_Speed: 1 92 | m_CycleOffset: 0 93 | m_Transitions: [] 94 | m_StateMachineBehaviours: 95 | - {fileID: -7719676013391324315} 96 | m_Position: {x: 50, y: 50, z: 0} 97 | m_IKOnFeet: 0 98 | m_WriteDefaultValues: 0 99 | m_Mirror: 0 100 | m_SpeedParameterActive: 0 101 | m_MirrorParameterActive: 0 102 | m_CycleOffsetParameterActive: 0 103 | m_TimeParameterActive: 0 104 | m_Motion: {fileID: 7400000, guid: 3e2ba1567477a42b3b2686183f7ce451, type: 2} 105 | m_Tag: 106 | m_SpeedParameter: 107 | m_MirrorParameter: 108 | m_CycleOffsetParameter: 109 | m_TimeParameter: 110 | --- !u!91 &9100000 111 | AnimatorController: 112 | m_ObjectHideFlags: 0 113 | m_CorrespondingSourceObject: {fileID: 0} 114 | m_PrefabInstance: {fileID: 0} 115 | m_PrefabAsset: {fileID: 0} 116 | m_Name: Mirror Detection FX 117 | serializedVersion: 5 118 | m_AnimatorParameters: 119 | - m_Name: IsLocal 120 | m_Type: 4 121 | m_DefaultFloat: 0 122 | m_DefaultInt: 0 123 | m_DefaultBool: 0 124 | m_Controller: {fileID: 0} 125 | - m_Name: MirrorDetection/DetectMirror 126 | m_Type: 4 127 | m_DefaultFloat: 0 128 | m_DefaultInt: 0 129 | m_DefaultBool: 0 130 | m_Controller: {fileID: 0} 131 | - m_Name: MirrorDetection/IsMirror 132 | m_Type: 1 133 | m_DefaultFloat: 0 134 | m_DefaultInt: 0 135 | m_DefaultBool: 0 136 | m_Controller: {fileID: 0} 137 | m_AnimatorLayers: 138 | - serializedVersion: 5 139 | m_Name: Local Mirror Detection 140 | m_StateMachine: {fileID: 5094055962389404326} 141 | m_Mask: {fileID: 0} 142 | m_Motions: [] 143 | m_Behaviours: [] 144 | m_BlendingMode: 0 145 | m_SyncedLayerIndex: -1 146 | m_DefaultWeight: 1 147 | m_IKPass: 0 148 | m_SyncedLayerAffectsTiming: 0 149 | m_Controller: {fileID: 9100000} 150 | --- !u!1102 &297040634560182215 151 | AnimatorState: 152 | serializedVersion: 6 153 | m_ObjectHideFlags: 1 154 | m_CorrespondingSourceObject: {fileID: 0} 155 | m_PrefabInstance: {fileID: 0} 156 | m_PrefabAsset: {fileID: 0} 157 | m_Name: Mirror 158 | m_Speed: 1 159 | m_CycleOffset: 0 160 | m_Transitions: [] 161 | m_StateMachineBehaviours: [] 162 | m_Position: {x: 50, y: 50, z: 0} 163 | m_IKOnFeet: 0 164 | m_WriteDefaultValues: 0 165 | m_Mirror: 0 166 | m_SpeedParameterActive: 0 167 | m_MirrorParameterActive: 0 168 | m_CycleOffsetParameterActive: 0 169 | m_TimeParameterActive: 0 170 | m_Motion: {fileID: 7400000, guid: 87293e88fb37f4cc6912d2aa42ccc08e, type: 2} 171 | m_Tag: 172 | m_SpeedParameter: 173 | m_MirrorParameter: 174 | m_CycleOffsetParameter: 175 | m_TimeParameter: 176 | --- !u!1101 &1603005695119593288 177 | AnimatorStateTransition: 178 | m_ObjectHideFlags: 1 179 | m_CorrespondingSourceObject: {fileID: 0} 180 | m_PrefabInstance: {fileID: 0} 181 | m_PrefabAsset: {fileID: 0} 182 | m_Name: 183 | m_Conditions: 184 | - m_ConditionMode: 2 185 | m_ConditionEvent: IsLocal 186 | m_EventTreshold: 0 187 | m_DstStateMachine: {fileID: 0} 188 | m_DstState: {fileID: 7396059198905066274} 189 | m_Solo: 0 190 | m_Mute: 0 191 | m_IsExit: 0 192 | serializedVersion: 3 193 | m_TransitionDuration: 0 194 | m_TransitionOffset: 0 195 | m_ExitTime: 1 196 | m_HasExitTime: 0 197 | m_HasFixedDuration: 0 198 | m_InterruptionSource: 0 199 | m_OrderedInterruption: 1 200 | m_CanTransitionToSelf: 1 201 | --- !u!1101 &3107862120337283806 202 | AnimatorStateTransition: 203 | m_ObjectHideFlags: 1 204 | m_CorrespondingSourceObject: {fileID: 0} 205 | m_PrefabInstance: {fileID: 0} 206 | m_PrefabAsset: {fileID: 0} 207 | m_Name: 208 | m_Conditions: 209 | - m_ConditionMode: 1 210 | m_ConditionEvent: MirrorDetection/DetectMirror 211 | m_EventTreshold: 0 212 | m_DstStateMachine: {fileID: 0} 213 | m_DstState: {fileID: 297040634560182215} 214 | m_Solo: 0 215 | m_Mute: 0 216 | m_IsExit: 0 217 | serializedVersion: 3 218 | m_TransitionDuration: 0 219 | m_TransitionOffset: 0 220 | m_ExitTime: 1 221 | m_HasExitTime: 0 222 | m_HasFixedDuration: 0 223 | m_InterruptionSource: 0 224 | m_OrderedInterruption: 1 225 | m_CanTransitionToSelf: 1 226 | --- !u!1107 &5094055962389404326 227 | AnimatorStateMachine: 228 | serializedVersion: 6 229 | m_ObjectHideFlags: 1 230 | m_CorrespondingSourceObject: {fileID: 0} 231 | m_PrefabInstance: {fileID: 0} 232 | m_PrefabAsset: {fileID: 0} 233 | m_Name: Local Mirror Detection 234 | m_ChildStates: 235 | - serializedVersion: 1 236 | m_State: {fileID: 5701009222351216330} 237 | m_Position: {x: 30, y: 180, z: 0} 238 | - serializedVersion: 1 239 | m_State: {fileID: -9049777313585539016} 240 | m_Position: {x: 30, y: 250, z: 0} 241 | - serializedVersion: 1 242 | m_State: {fileID: 297040634560182215} 243 | m_Position: {x: -90, y: 320, z: 0} 244 | - serializedVersion: 1 245 | m_State: {fileID: -2948385516909857121} 246 | m_Position: {x: 150, y: 320, z: 0} 247 | - serializedVersion: 1 248 | m_State: {fileID: 7396059198905066274} 249 | m_Position: {x: 270, y: 180, z: 0} 250 | m_ChildStateMachines: [] 251 | m_AnyStateTransitions: [] 252 | m_EntryTransitions: [] 253 | m_StateMachineTransitions: {} 254 | m_StateMachineBehaviours: [] 255 | m_AnyStatePosition: {x: 50, y: 40, z: 0} 256 | m_EntryPosition: {x: 50, y: 120, z: 0} 257 | m_ExitPosition: {x: 50, y: 80, z: 0} 258 | m_ParentStateMachinePosition: {x: 800, y: 20, z: 0} 259 | m_DefaultState: {fileID: 5701009222351216330} 260 | --- !u!1101 &5469010140199689570 261 | AnimatorStateTransition: 262 | m_ObjectHideFlags: 1 263 | m_CorrespondingSourceObject: {fileID: 0} 264 | m_PrefabInstance: {fileID: 0} 265 | m_PrefabAsset: {fileID: 0} 266 | m_Name: 267 | m_Conditions: 268 | - m_ConditionMode: 1 269 | m_ConditionEvent: IsLocal 270 | m_EventTreshold: 0 271 | m_DstStateMachine: {fileID: 0} 272 | m_DstState: {fileID: -9049777313585539016} 273 | m_Solo: 0 274 | m_Mute: 0 275 | m_IsExit: 0 276 | serializedVersion: 3 277 | m_TransitionDuration: 0 278 | m_TransitionOffset: 0 279 | m_ExitTime: 1 280 | m_HasExitTime: 0 281 | m_HasFixedDuration: 0 282 | m_InterruptionSource: 0 283 | m_OrderedInterruption: 1 284 | m_CanTransitionToSelf: 1 285 | --- !u!1102 &5701009222351216330 286 | AnimatorState: 287 | serializedVersion: 6 288 | m_ObjectHideFlags: 1 289 | m_CorrespondingSourceObject: {fileID: 0} 290 | m_PrefabInstance: {fileID: 0} 291 | m_PrefabAsset: {fileID: 0} 292 | m_Name: Init 293 | m_Speed: 1 294 | m_CycleOffset: 0 295 | m_Transitions: 296 | - {fileID: 5469010140199689570} 297 | - {fileID: 1603005695119593288} 298 | m_StateMachineBehaviours: [] 299 | m_Position: {x: 50, y: 50, z: 0} 300 | m_IKOnFeet: 0 301 | m_WriteDefaultValues: 0 302 | m_Mirror: 0 303 | m_SpeedParameterActive: 0 304 | m_MirrorParameterActive: 0 305 | m_CycleOffsetParameterActive: 0 306 | m_TimeParameterActive: 0 307 | m_Motion: {fileID: 7400000, guid: 26ee6725878c84a4ca5ba99b28042ac4, type: 2} 308 | m_Tag: 309 | m_SpeedParameter: 310 | m_MirrorParameter: 311 | m_CycleOffsetParameter: 312 | m_TimeParameter: 313 | --- !u!1102 &7396059198905066274 314 | AnimatorState: 315 | serializedVersion: 6 316 | m_ObjectHideFlags: 1 317 | m_CorrespondingSourceObject: {fileID: 0} 318 | m_PrefabInstance: {fileID: 0} 319 | m_PrefabAsset: {fileID: 0} 320 | m_Name: Remote 321 | m_Speed: 1 322 | m_CycleOffset: 0 323 | m_Transitions: [] 324 | m_StateMachineBehaviours: [] 325 | m_Position: {x: 50, y: 50, z: 0} 326 | m_IKOnFeet: 0 327 | m_WriteDefaultValues: 0 328 | m_Mirror: 0 329 | m_SpeedParameterActive: 0 330 | m_MirrorParameterActive: 0 331 | m_CycleOffsetParameterActive: 0 332 | m_TimeParameterActive: 0 333 | m_Motion: {fileID: 7400000, guid: 3e2ba1567477a42b3b2686183f7ce451, type: 2} 334 | m_Tag: 335 | m_SpeedParameter: 336 | m_MirrorParameter: 337 | m_CycleOffsetParameter: 338 | m_TimeParameter: 339 | -------------------------------------------------------------------------------- /Mirror Detection FX.controller.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 980b44fa3d7e748ae9d644959c0f1653 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | # Local Mirror Detection 4 | 5 | [![Generic badge](https://img.shields.io/github/downloads/VRLabs/Local-Mirror-Detection/total?label=Downloads)](https://github.com/VRLabs/Local-Mirror-Detection/releases/latest) 6 | [![Generic badge](https://img.shields.io/badge/License-MIT-informational.svg)](https://github.com/VRLabs/Local-Mirror-Detection/blob/main/LICENSE) 7 | [![Generic badge](https://img.shields.io/badge/Quest-Compatible-green?logo=Meta)](https://img.shields.io/badge/Quest-Compatible-green?logo=Meta) 8 | [![Generic badge](https://img.shields.io/badge/Unity-2022.3.22f1-lightblue?logo=Unity)](https://unity.com/releases/editor/whats-new/2022.3.22) 9 | [![Generic badge](https://img.shields.io/badge/SDK-AvatarSDK3-lightblue.svg)](https://vrchat.com/home/download) 10 | 11 | [![Generic badge](https://img.shields.io/discord/706913824607043605?color=%237289da&label=DISCORD&logo=Discord&style=for-the-badge)](https://discord.vrlabs.dev/) 12 | [![Generic badge](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fshieldsio-patreon.vercel.app%2Fapi%3Fusername%3Dvrlabs%26type%3Dpatrons&style=for-the-badge)](https://patreon.vrlabs.dev/) 13 | 14 | Sets an "IsMirror" parameter to true on your mirror clone 15 | 16 | ![VRChat_2023-10-25_20-51-13 163_3840x2160](https://github.com/VRLabs/Local-Mirror-Detection/assets/76777936/2e9e5f00-6b90-40f6-9c8e-44b7be6dd610) 17 | 18 | ### ⬇️ [Download Latest Version](https://github.com/VRLabs/Local-Mirror-Detection/releases/latest) 19 | 20 | ### 📦 [Add to VRChat Creator Companion](https://vrlabs.dev/packages?package=dev.vrlabs.local-mirror-detection) 21 | 22 |
23 | 24 | --- 25 | 26 | ## How it works 27 | 28 | * The mirror clone initializes after the local clone by copying the local clone in its current state. 29 | * By changing the value of a parameter before the mirror clone initializes, we can desync the two clones in the FX Controller. 30 | 31 | ## Install guide 32 | 33 | https://github.com/VRLabs/Local-Mirror-Detection/assets/76777936/f225e58d-5863-4e29-ae00-87bf8f4bfde5 34 | 35 | * Merge the Animator Controller ``Mirror Detection FX`` to your own FX Controller, using the [Avatars 3.0 Manager](https://github.com/VRLabs/Avatars-3.0-Manager) tool. 36 | 37 | ## How to use 38 | 39 | * The ``IsMirror`` parameter is a float. The value will be 1.0 on the mirror clone and -1.0 on your local clone. 40 | * You can use this float to play animations for only your mirror clone 41 | * Note that you can not animate transforms on your mirror clone 42 | 43 | ## Performance stats 44 | 45 | ```c++ 46 | FX Animator Layers: 1 47 | ``` 48 | 49 | ## Contributors 50 | 51 | [Dreadrith](https://github.com/Dreadrith) 52 | 53 | ## License 54 | 55 | Local Mirror Detection is available as-is under MIT. For more information see [LICENSE](https://github.com/VRLabs/Local-Mirror-Detection/blob/main/LICENSE). 56 | 57 | ​ 58 | 59 |
60 | 61 | [](https://vrlabs.dev "VRLabs") 62 | 63 | [](https://discord.vrlabs.dev/ "VRLabs") 64 | 65 | [](https://patreon.vrlabs.dev/ "VRLabs") 66 | 67 | [](https://twitter.com/vrlabsdev "VRLabs") 68 | 69 |
70 | -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3afad631f29c1414891fc3db10b2a5d9 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Resources.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 53803d59b41314102bda9158ef119b59 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Resources/Animations.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 27d192d7c029d7c42b4c7626e97905c0 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Resources/Animations/Mirror Detection Buffer.anim: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!74 &7400000 4 | AnimationClip: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_Name: Mirror Detection Buffer 10 | serializedVersion: 6 11 | m_Legacy: 0 12 | m_Compressed: 0 13 | m_UseHighQualityCurve: 1 14 | m_RotationCurves: [] 15 | m_CompressedRotationCurves: [] 16 | m_EulerCurves: [] 17 | m_PositionCurves: [] 18 | m_ScaleCurves: [] 19 | m_FloatCurves: 20 | - curve: 21 | serializedVersion: 2 22 | m_Curve: 23 | - serializedVersion: 3 24 | time: 0 25 | value: 0 26 | inSlope: Infinity 27 | outSlope: Infinity 28 | tangentMode: 103 29 | weightedMode: 0 30 | inWeight: 0.33333334 31 | outWeight: 0.33333334 32 | - serializedVersion: 3 33 | time: 1 34 | value: 0 35 | inSlope: Infinity 36 | outSlope: Infinity 37 | tangentMode: 103 38 | weightedMode: 0 39 | inWeight: 0.33333334 40 | outWeight: 0.33333334 41 | m_PreInfinity: 2 42 | m_PostInfinity: 2 43 | m_RotationOrder: 4 44 | attribute: m_IsActive 45 | path: _Buffer 46 | classID: 1 47 | script: {fileID: 0} 48 | m_PPtrCurves: [] 49 | m_SampleRate: 60 50 | m_WrapMode: 0 51 | m_Bounds: 52 | m_Center: {x: 0, y: 0, z: 0} 53 | m_Extent: {x: 0, y: 0, z: 0} 54 | m_ClipBindingConstant: 55 | genericBindings: 56 | - serializedVersion: 2 57 | path: 3485798983 58 | attribute: 2086281974 59 | script: {fileID: 0} 60 | typeID: 1 61 | customType: 0 62 | isPPtrCurve: 0 63 | pptrCurveMapping: [] 64 | m_AnimationClipSettings: 65 | serializedVersion: 2 66 | m_AdditiveReferencePoseClip: {fileID: 0} 67 | m_AdditiveReferencePoseTime: 0 68 | m_StartTime: 0 69 | m_StopTime: 1 70 | m_OrientationOffsetY: 0 71 | m_Level: 0 72 | m_CycleOffset: 0 73 | m_HasAdditiveReferencePose: 0 74 | m_LoopTime: 0 75 | m_LoopBlend: 0 76 | m_LoopBlendOrientation: 0 77 | m_LoopBlendPositionY: 0 78 | m_LoopBlendPositionXZ: 0 79 | m_KeepOriginalOrientation: 0 80 | m_KeepOriginalPositionY: 1 81 | m_KeepOriginalPositionXZ: 0 82 | m_HeightFromFeet: 0 83 | m_Mirror: 0 84 | m_EditorCurves: 85 | - curve: 86 | serializedVersion: 2 87 | m_Curve: 88 | - serializedVersion: 3 89 | time: 0 90 | value: 0 91 | inSlope: Infinity 92 | outSlope: Infinity 93 | tangentMode: 103 94 | weightedMode: 0 95 | inWeight: 0.33333334 96 | outWeight: 0.33333334 97 | - serializedVersion: 3 98 | time: 1 99 | value: 0 100 | inSlope: Infinity 101 | outSlope: Infinity 102 | tangentMode: 103 103 | weightedMode: 0 104 | inWeight: 0.33333334 105 | outWeight: 0.33333334 106 | m_PreInfinity: 2 107 | m_PostInfinity: 2 108 | m_RotationOrder: 4 109 | attribute: m_IsActive 110 | path: _Buffer 111 | classID: 1 112 | script: {fileID: 0} 113 | m_EulerEditorCurves: [] 114 | m_HasGenericRootTransform: 0 115 | m_HasMotionFloatCurves: 0 116 | m_Events: [] 117 | -------------------------------------------------------------------------------- /Resources/Animations/Mirror Detection Buffer.anim.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 26ee6725878c84a4ca5ba99b28042ac4 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Resources/Animations/Mirror Detection False.anim: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!74 &7400000 4 | AnimationClip: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_Name: Mirror Detection False 10 | serializedVersion: 6 11 | m_Legacy: 0 12 | m_Compressed: 0 13 | m_UseHighQualityCurve: 1 14 | m_RotationCurves: [] 15 | m_CompressedRotationCurves: [] 16 | m_EulerCurves: [] 17 | m_PositionCurves: [] 18 | m_ScaleCurves: [] 19 | m_FloatCurves: 20 | - curve: 21 | serializedVersion: 2 22 | m_Curve: 23 | - serializedVersion: 3 24 | time: 0 25 | value: -1 26 | inSlope: Infinity 27 | outSlope: Infinity 28 | tangentMode: 103 29 | weightedMode: 0 30 | inWeight: 0.33333334 31 | outWeight: 0.33333334 32 | - serializedVersion: 3 33 | time: 1 34 | value: -1 35 | inSlope: Infinity 36 | outSlope: Infinity 37 | tangentMode: 103 38 | weightedMode: 0 39 | inWeight: 0.33333334 40 | outWeight: 0.33333334 41 | m_PreInfinity: 2 42 | m_PostInfinity: 2 43 | m_RotationOrder: 4 44 | attribute: MirrorDetection/IsMirror 45 | path: 46 | classID: 95 47 | script: {fileID: 0} 48 | m_PPtrCurves: [] 49 | m_SampleRate: 60 50 | m_WrapMode: 0 51 | m_Bounds: 52 | m_Center: {x: 0, y: 0, z: 0} 53 | m_Extent: {x: 0, y: 0, z: 0} 54 | m_ClipBindingConstant: 55 | genericBindings: 56 | - serializedVersion: 2 57 | path: 0 58 | attribute: 1360224260 59 | script: {fileID: 0} 60 | typeID: 95 61 | customType: 0 62 | isPPtrCurve: 0 63 | pptrCurveMapping: [] 64 | m_AnimationClipSettings: 65 | serializedVersion: 2 66 | m_AdditiveReferencePoseClip: {fileID: 0} 67 | m_AdditiveReferencePoseTime: 0 68 | m_StartTime: 0 69 | m_StopTime: 1 70 | m_OrientationOffsetY: 0 71 | m_Level: 0 72 | m_CycleOffset: 0 73 | m_HasAdditiveReferencePose: 0 74 | m_LoopTime: 0 75 | m_LoopBlend: 0 76 | m_LoopBlendOrientation: 0 77 | m_LoopBlendPositionY: 0 78 | m_LoopBlendPositionXZ: 0 79 | m_KeepOriginalOrientation: 0 80 | m_KeepOriginalPositionY: 1 81 | m_KeepOriginalPositionXZ: 0 82 | m_HeightFromFeet: 0 83 | m_Mirror: 0 84 | m_EditorCurves: 85 | - curve: 86 | serializedVersion: 2 87 | m_Curve: 88 | - serializedVersion: 3 89 | time: 0 90 | value: -1 91 | inSlope: Infinity 92 | outSlope: Infinity 93 | tangentMode: 103 94 | weightedMode: 0 95 | inWeight: 0.33333334 96 | outWeight: 0.33333334 97 | - serializedVersion: 3 98 | time: 1 99 | value: -1 100 | inSlope: Infinity 101 | outSlope: Infinity 102 | tangentMode: 103 103 | weightedMode: 0 104 | inWeight: 0.33333334 105 | outWeight: 0.33333334 106 | m_PreInfinity: 2 107 | m_PostInfinity: 2 108 | m_RotationOrder: 4 109 | attribute: MirrorDetection/IsMirror 110 | path: 111 | classID: 95 112 | script: {fileID: 0} 113 | m_EulerEditorCurves: [] 114 | m_HasGenericRootTransform: 0 115 | m_HasMotionFloatCurves: 0 116 | m_Events: [] 117 | -------------------------------------------------------------------------------- /Resources/Animations/Mirror Detection False.anim.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3e2ba1567477a42b3b2686183f7ce451 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Resources/Animations/Mirror Detection True.anim: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!74 &7400000 4 | AnimationClip: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_Name: Mirror Detection True 10 | serializedVersion: 6 11 | m_Legacy: 0 12 | m_Compressed: 0 13 | m_UseHighQualityCurve: 1 14 | m_RotationCurves: [] 15 | m_CompressedRotationCurves: [] 16 | m_EulerCurves: [] 17 | m_PositionCurves: [] 18 | m_ScaleCurves: [] 19 | m_FloatCurves: 20 | - curve: 21 | serializedVersion: 2 22 | m_Curve: 23 | - serializedVersion: 3 24 | time: 0 25 | value: 1 26 | inSlope: Infinity 27 | outSlope: Infinity 28 | tangentMode: 103 29 | weightedMode: 0 30 | inWeight: 0.33333334 31 | outWeight: 0.33333334 32 | - serializedVersion: 3 33 | time: 1 34 | value: 1 35 | inSlope: Infinity 36 | outSlope: Infinity 37 | tangentMode: 103 38 | weightedMode: 0 39 | inWeight: 0.33333334 40 | outWeight: 0.33333334 41 | m_PreInfinity: 2 42 | m_PostInfinity: 2 43 | m_RotationOrder: 4 44 | attribute: MirrorDetection/IsMirror 45 | path: 46 | classID: 95 47 | script: {fileID: 0} 48 | m_PPtrCurves: [] 49 | m_SampleRate: 60 50 | m_WrapMode: 0 51 | m_Bounds: 52 | m_Center: {x: 0, y: 0, z: 0} 53 | m_Extent: {x: 0, y: 0, z: 0} 54 | m_ClipBindingConstant: 55 | genericBindings: 56 | - serializedVersion: 2 57 | path: 0 58 | attribute: 1360224260 59 | script: {fileID: 0} 60 | typeID: 95 61 | customType: 0 62 | isPPtrCurve: 0 63 | pptrCurveMapping: [] 64 | m_AnimationClipSettings: 65 | serializedVersion: 2 66 | m_AdditiveReferencePoseClip: {fileID: 0} 67 | m_AdditiveReferencePoseTime: 0 68 | m_StartTime: 0 69 | m_StopTime: 1 70 | m_OrientationOffsetY: 0 71 | m_Level: 0 72 | m_CycleOffset: 0 73 | m_HasAdditiveReferencePose: 0 74 | m_LoopTime: 0 75 | m_LoopBlend: 0 76 | m_LoopBlendOrientation: 0 77 | m_LoopBlendPositionY: 0 78 | m_LoopBlendPositionXZ: 0 79 | m_KeepOriginalOrientation: 0 80 | m_KeepOriginalPositionY: 1 81 | m_KeepOriginalPositionXZ: 0 82 | m_HeightFromFeet: 0 83 | m_Mirror: 0 84 | m_EditorCurves: 85 | - curve: 86 | serializedVersion: 2 87 | m_Curve: 88 | - serializedVersion: 3 89 | time: 0 90 | value: 1 91 | inSlope: Infinity 92 | outSlope: Infinity 93 | tangentMode: 103 94 | weightedMode: 0 95 | inWeight: 0.33333334 96 | outWeight: 0.33333334 97 | - serializedVersion: 3 98 | time: 1 99 | value: 1 100 | inSlope: Infinity 101 | outSlope: Infinity 102 | tangentMode: 103 103 | weightedMode: 0 104 | inWeight: 0.33333334 105 | outWeight: 0.33333334 106 | m_PreInfinity: 2 107 | m_PostInfinity: 2 108 | m_RotationOrder: 4 109 | attribute: MirrorDetection/IsMirror 110 | path: 111 | classID: 95 112 | script: {fileID: 0} 113 | m_EulerEditorCurves: [] 114 | m_HasGenericRootTransform: 0 115 | m_HasMotionFloatCurves: 0 116 | m_Events: [] 117 | -------------------------------------------------------------------------------- /Resources/Animations/Mirror Detection True.anim.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 87293e88fb37f4cc6912d2aa42ccc08e 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dev.vrlabs.local-mirror-detection", 3 | "displayName": "Local Mirror Detection", 4 | "version": "1.0.999", 5 | "license": "MIT", 6 | "unity": "2022.3", 7 | "description": "Sets an \"IsMirror\" parameter to true on your mirror clone", 8 | "author": { 9 | "name": "VRLabs", 10 | "email": "mail@vrlabs.dev", 11 | "url": "https://vrlabs.dev" 12 | }, 13 | "siteUrl": "https://github.com/VRLabs/Local-Mirror-Detection", 14 | "vpmDependencies": { 15 | "dev.vrlabs.instancer": ">=1.0.2" 16 | }, 17 | "legacyFolders": { 18 | "Assets\\VRLabs\\Local Mirror Detection": "752b7e9b073124232a11f12753e8d120" 19 | }, 20 | "unityPackageDestinationFolder": "Assets/VRLabs/Local Mirror Detection", 21 | "vccRepoCategory": "components", 22 | "media": { 23 | "previewImage": "https://raw.githubusercontent.com/VRLabs/Local-Mirror-Detection/main/Media/Web/Preview.webp", 24 | "previewGif": "https://raw.githubusercontent.com/VRLabs/Local-Mirror-Detection/main/Media/Web/Preview.webp" 25 | }, 26 | "unityPackageDestinationFolderMetas": { 27 | "Assets/VRLabs": "652a1ba5b00554143bc9a76307dbc4e8", 28 | "Assets/VRLabs/Local Mirror Detection": "752b7e9b073124232a11f12753e8d120" 29 | }, 30 | "questCompatibility": "full" 31 | } -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fa031f68789ca614aacd1ca9e9e4736c 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | --------------------------------------------------------------------------------