├── .gitattributes ├── .gitignore ├── HauntedModMenu.sln ├── HauntedModMenu ├── Buttons │ ├── ButtonTrigger.cs │ ├── HandTrigger.cs │ ├── ModButtonTrigger.cs │ └── PageButtonTrigger.cs ├── Directory.Build.props ├── Directory.Build.targets ├── HarmonyPatches.cs ├── HauntedModMenu.csproj ├── MakeRelease.ps1 ├── Menu │ ├── MenuController.cs │ └── MenuView.cs ├── Plugin.cs ├── PluginInfo.cs ├── Resources │ └── font ├── TestPlugins.cs └── Utils │ ├── Cache.cs │ ├── Config.cs │ ├── ModInfo.cs │ └── ObjectTracker.cs ├── LICENSE └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *-v.zip 2 | 3 | ## Ignore Visual Studio temporary files, build results, and 4 | ## files generated by popular Visual Studio add-ons. 5 | ## 6 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 7 | 8 | # User-specific files 9 | *.rsuser 10 | *.suo 11 | *.user 12 | *.userosscache 13 | *.sln.docstates 14 | 15 | # User-specific files (MonoDevelop/Xamarin Studio) 16 | *.userprefs 17 | 18 | # Mono auto generated files 19 | mono_crash.* 20 | 21 | # Build results 22 | [Dd]ebug/ 23 | [Dd]ebugPublic/ 24 | [Rr]elease/ 25 | [Rr]eleases/ 26 | x64/ 27 | x86/ 28 | [Ww][Ii][Nn]32/ 29 | [Aa][Rr][Mm]/ 30 | [Aa][Rr][Mm]64/ 31 | bld/ 32 | [Bb]in/ 33 | [Oo]bj/ 34 | [Ll]og/ 35 | [Ll]ogs/ 36 | 37 | # Visual Studio 2015/2017 cache/options directory 38 | .vs/ 39 | # Uncomment if you have tasks that create the project's static files in wwwroot 40 | #wwwroot/ 41 | 42 | # Visual Studio 2017 auto generated files 43 | Generated\ Files/ 44 | 45 | # MSTest test Results 46 | [Tt]est[Rr]esult*/ 47 | [Bb]uild[Ll]og.* 48 | 49 | # NUnit 50 | *.VisualState.xml 51 | TestResult.xml 52 | nunit-*.xml 53 | 54 | # Build Results of an ATL Project 55 | [Dd]ebugPS/ 56 | [Rr]eleasePS/ 57 | dlldata.c 58 | 59 | # Benchmark Results 60 | BenchmarkDotNet.Artifacts/ 61 | 62 | # .NET Core 63 | project.lock.json 64 | project.fragment.lock.json 65 | artifacts/ 66 | 67 | # ASP.NET Scaffolding 68 | ScaffoldingReadMe.txt 69 | 70 | # StyleCop 71 | StyleCopReport.xml 72 | 73 | # Files built by Visual Studio 74 | *_i.c 75 | *_p.c 76 | *_h.h 77 | *.ilk 78 | *.meta 79 | *.obj 80 | *.iobj 81 | *.pch 82 | *.pdb 83 | *.ipdb 84 | *.pgc 85 | *.pgd 86 | *.rsp 87 | *.sbr 88 | *.tlb 89 | *.tli 90 | *.tlh 91 | *.tmp 92 | *.tmp_proj 93 | *_wpftmp.csproj 94 | *.log 95 | *.tlog 96 | *.vspscc 97 | *.vssscc 98 | .builds 99 | *.pidb 100 | *.svclog 101 | *.scc 102 | 103 | # Chutzpah Test files 104 | _Chutzpah* 105 | 106 | # Visual C++ cache files 107 | ipch/ 108 | *.aps 109 | *.ncb 110 | *.opendb 111 | *.opensdf 112 | *.sdf 113 | *.cachefile 114 | *.VC.db 115 | *.VC.VC.opendb 116 | 117 | # Visual Studio profiler 118 | *.psess 119 | *.vsp 120 | *.vspx 121 | *.sap 122 | 123 | # Visual Studio Trace Files 124 | *.e2e 125 | 126 | # TFS 2012 Local Workspace 127 | $tf/ 128 | 129 | # Guidance Automation Toolkit 130 | *.gpState 131 | 132 | # ReSharper is a .NET coding add-in 133 | _ReSharper*/ 134 | *.[Rr]e[Ss]harper 135 | *.DotSettings.user 136 | 137 | # TeamCity is a build add-in 138 | _TeamCity* 139 | 140 | # DotCover is a Code Coverage Tool 141 | *.dotCover 142 | 143 | # AxoCover is a Code Coverage Tool 144 | .axoCover/* 145 | !.axoCover/settings.json 146 | 147 | # Coverlet is a free, cross platform Code Coverage Tool 148 | coverage*.json 149 | coverage*.xml 150 | coverage*.info 151 | 152 | # Visual Studio code coverage results 153 | *.coverage 154 | *.coveragexml 155 | 156 | # NCrunch 157 | _NCrunch_* 158 | .*crunch*.local.xml 159 | nCrunchTemp_* 160 | 161 | # MightyMoose 162 | *.mm.* 163 | AutoTest.Net/ 164 | 165 | # Web workbench (sass) 166 | .sass-cache/ 167 | 168 | # Installshield output folder 169 | [Ee]xpress/ 170 | 171 | # DocProject is a documentation generator add-in 172 | DocProject/buildhelp/ 173 | DocProject/Help/*.HxT 174 | DocProject/Help/*.HxC 175 | DocProject/Help/*.hhc 176 | DocProject/Help/*.hhk 177 | DocProject/Help/*.hhp 178 | DocProject/Help/Html2 179 | DocProject/Help/html 180 | 181 | # Click-Once directory 182 | publish/ 183 | 184 | # Publish Web Output 185 | *.[Pp]ublish.xml 186 | *.azurePubxml 187 | # Note: Comment the next line if you want to checkin your web deploy settings, 188 | # but database connection strings (with potential passwords) will be unencrypted 189 | *.pubxml 190 | *.publishproj 191 | 192 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 193 | # checkin your Azure Web App publish settings, but sensitive information contained 194 | # in these scripts will be unencrypted 195 | PublishScripts/ 196 | 197 | # NuGet Packages 198 | *.nupkg 199 | # NuGet Symbol Packages 200 | *.snupkg 201 | # The packages folder can be ignored because of Package Restore 202 | **/[Pp]ackages/* 203 | # except build/, which is used as an MSBuild target. 204 | !**/[Pp]ackages/build/ 205 | # Uncomment if necessary however generally it will be regenerated when needed 206 | #!**/[Pp]ackages/repositories.config 207 | # NuGet v3's project.json files produces more ignorable files 208 | *.nuget.props 209 | *.nuget.targets 210 | 211 | # Nuget personal access tokens and Credentials 212 | nuget.config 213 | 214 | # Microsoft Azure Build Output 215 | csx/ 216 | *.build.csdef 217 | 218 | # Microsoft Azure Emulator 219 | ecf/ 220 | rcf/ 221 | 222 | # Windows Store app package directories and files 223 | AppPackages/ 224 | BundleArtifacts/ 225 | Package.StoreAssociation.xml 226 | _pkginfo.txt 227 | *.appx 228 | *.appxbundle 229 | *.appxupload 230 | 231 | # Visual Studio cache files 232 | # files ending in .cache can be ignored 233 | *.[Cc]ache 234 | # but keep track of directories ending in .cache 235 | !?*.[Cc]ache/ 236 | 237 | # Others 238 | ClientBin/ 239 | ~$* 240 | *~ 241 | *.dbmdl 242 | *.dbproj.schemaview 243 | *.jfm 244 | *.pfx 245 | *.publishsettings 246 | orleans.codegen.cs 247 | 248 | # Including strong name files can present a security risk 249 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 250 | #*.snk 251 | 252 | # Since there are multiple workflows, uncomment next line to ignore bower_components 253 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 254 | #bower_components/ 255 | 256 | # RIA/Silverlight projects 257 | Generated_Code/ 258 | 259 | # Backup & report files from converting an old project file 260 | # to a newer Visual Studio version. Backup files are not needed, 261 | # because we have git ;-) 262 | _UpgradeReport_Files/ 263 | Backup*/ 264 | UpgradeLog*.XML 265 | UpgradeLog*.htm 266 | ServiceFabricBackup/ 267 | *.rptproj.bak 268 | 269 | # SQL Server files 270 | *.mdf 271 | *.ldf 272 | *.ndf 273 | 274 | # Business Intelligence projects 275 | *.rdl.data 276 | *.bim.layout 277 | *.bim_*.settings 278 | *.rptproj.rsuser 279 | *- [Bb]ackup.rdl 280 | *- [Bb]ackup ([0-9]).rdl 281 | *- [Bb]ackup ([0-9][0-9]).rdl 282 | 283 | # Microsoft Fakes 284 | FakesAssemblies/ 285 | 286 | # GhostDoc plugin setting file 287 | *.GhostDoc.xml 288 | 289 | # Node.js Tools for Visual Studio 290 | .ntvs_analysis.dat 291 | node_modules/ 292 | 293 | # Visual Studio 6 build log 294 | *.plg 295 | 296 | # Visual Studio 6 workspace options file 297 | *.opt 298 | 299 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 300 | *.vbw 301 | 302 | # Visual Studio LightSwitch build output 303 | **/*.HTMLClient/GeneratedArtifacts 304 | **/*.DesktopClient/GeneratedArtifacts 305 | **/*.DesktopClient/ModelManifest.xml 306 | **/*.Server/GeneratedArtifacts 307 | **/*.Server/ModelManifest.xml 308 | _Pvt_Extensions 309 | 310 | # Paket dependency manager 311 | .paket/paket.exe 312 | paket-files/ 313 | 314 | # FAKE - F# Make 315 | .fake/ 316 | 317 | # CodeRush personal settings 318 | .cr/personal 319 | 320 | # Python Tools for Visual Studio (PTVS) 321 | __pycache__/ 322 | *.pyc 323 | 324 | # Cake - Uncomment if you are using it 325 | # tools/** 326 | # !tools/packages.config 327 | 328 | # Tabs Studio 329 | *.tss 330 | 331 | # Telerik's JustMock configuration file 332 | *.jmconfig 333 | 334 | # BizTalk build output 335 | *.btp.cs 336 | *.btm.cs 337 | *.odx.cs 338 | *.xsd.cs 339 | 340 | # OpenCover UI analysis results 341 | OpenCover/ 342 | 343 | # Azure Stream Analytics local run output 344 | ASALocalRun/ 345 | 346 | # MSBuild Binary and Structured Log 347 | *.binlog 348 | 349 | # NVidia Nsight GPU debugger configuration file 350 | *.nvuser 351 | 352 | # MFractors (Xamarin productivity tool) working folder 353 | .mfractor/ 354 | 355 | # Local History for Visual Studio 356 | .localhistory/ 357 | 358 | # BeatPulse healthcheck temp database 359 | healthchecksdb 360 | 361 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 362 | MigrationBackup/ 363 | 364 | # Ionide (cross platform F# VS Code tools) working folder 365 | .ionide/ 366 | 367 | # Fody - auto-generated XML schema 368 | FodyWeavers.xsd 369 | 370 | # VS Code files for those working on multiple tools 371 | .vscode/* 372 | !.vscode/settings.json 373 | !.vscode/tasks.json 374 | !.vscode/launch.json 375 | !.vscode/extensions.json 376 | *.code-workspace 377 | 378 | # Local History for Visual Studio Code 379 | .history/ 380 | 381 | # Windows Installer files from build outputs 382 | *.cab 383 | *.msi 384 | *.msix 385 | *.msm 386 | *.msp 387 | 388 | # JetBrains Rider 389 | .idea/ 390 | *.sln.iml 391 | 392 | *.zip 393 | -------------------------------------------------------------------------------- /HauntedModMenu.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31829.152 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HauntedModMenu", "HauntedModMenu\HauntedModMenu.csproj", "{819AC7A6-D544-4782-A8A7-68DD6165414E}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {819AC7A6-D544-4782-A8A7-68DD6165414E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {819AC7A6-D544-4782-A8A7-68DD6165414E}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {819AC7A6-D544-4782-A8A7-68DD6165414E}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {819AC7A6-D544-4782-A8A7-68DD6165414E}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {5EA6DF80-C1D8-4B04-BFEE-3DFA7FFDC427} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /HauntedModMenu/Buttons/ButtonTrigger.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.UI; 3 | 4 | namespace HauntedModMenu.Buttons 5 | { 6 | class ButtonTrigger : HandTrigger 7 | { 8 | public Color EnabledColor { get; set; } 9 | public Color DisabledColor { get; set; } 10 | public Text ButtonText { get; private set; } 11 | public Material ButtonMaterial { get; private set; } 12 | 13 | protected override void Awake() 14 | { 15 | base.Awake(); 16 | 17 | ButtonText = this.gameObject.GetComponentInChildren(); 18 | ButtonMaterial = this.gameObject.GetComponent()?.material; 19 | } 20 | 21 | public void SetColour(bool enabled) 22 | { 23 | if (ButtonMaterial == null) 24 | return; 25 | 26 | ButtonMaterial.SetColor("_Color", enabled ? EnabledColor : DisabledColor); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /HauntedModMenu/Buttons/HandTrigger.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | 3 | using UnityEngine; 4 | 5 | namespace HauntedModMenu.Buttons 6 | { 7 | internal class HandTrigger : MonoBehaviour 8 | { 9 | protected bool triggered = false; 10 | protected Collider handCollider = null; 11 | 12 | protected static bool leftHand = true; 13 | protected static float handSensitivity = 1f; 14 | protected static Utils.ObjectTracker leftHandTracker = null; 15 | protected static Utils.ObjectTracker rightHandTracker = null; 16 | 17 | private Coroutine timerRoutine = null; 18 | 19 | protected virtual void Awake() 20 | { 21 | this.gameObject.layer = LayerMask.NameToLayer("GorillaInteractable"); 22 | 23 | if(leftHandTracker == null) 24 | leftHandTracker = Utils.RefCache.LeftHandFollower?.AddComponent(); 25 | 26 | if(rightHandTracker == null) 27 | rightHandTracker = Utils.RefCache.RightHandFollower?.AddComponent(); 28 | } 29 | 30 | protected virtual void OnDisable() 31 | { 32 | triggered = false; 33 | if(timerRoutine != null) 34 | StopCoroutine(timerRoutine); 35 | } 36 | 37 | private void OnTriggerEnter(Collider collider) 38 | { 39 | if (triggered) 40 | return; 41 | 42 | GorillaTriggerColliderHandIndicator hand = collider.GetComponentInParent(); 43 | if (hand == null) 44 | return; 45 | 46 | float lhSpeed = leftHandTracker != null ? leftHandTracker.Speed : 0f; 47 | float rhSpeed = rightHandTracker != null ? rightHandTracker.Speed : 0f; 48 | 49 | bool canTrigger = lhSpeed < handSensitivity && rhSpeed < handSensitivity; 50 | 51 | if (canTrigger && hand.isLeftHand != leftHand) { 52 | triggered = true; 53 | handCollider = collider; 54 | 55 | GorillaTagger.Instance.StartVibration(hand.isLeftHand, GorillaTagger.Instance.tapHapticStrength / 2f, GorillaTagger.Instance.tapHapticDuration); 56 | 57 | timerRoutine = StartCoroutine(Timer()); 58 | HandTriggered(); 59 | } 60 | } 61 | 62 | private IEnumerator Timer() 63 | { 64 | yield return new WaitForSeconds(1.5f); 65 | triggered = false; 66 | timerRoutine = null; 67 | } 68 | 69 | protected virtual void HandTriggered() { } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /HauntedModMenu/Buttons/ModButtonTrigger.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace HauntedModMenu.Buttons 4 | { 5 | class ModButtonTrigger : ButtonTrigger 6 | { 7 | private Utils.ModInfo modTarget = null; 8 | public Utils.ModInfo ModTarget { 9 | get => modTarget; 10 | set { 11 | modTarget = value; 12 | 13 | if (value != null) { 14 | SetColour(value.Enabled); 15 | 16 | } else { 17 | SetColour(false); 18 | } 19 | } 20 | } 21 | 22 | protected override void HandTriggered() 23 | { 24 | if (modTarget == null) return; 25 | 26 | bool toEnable = !modTarget.Enabled; 27 | modTarget.Enabled = toEnable; 28 | SetColour(toEnable); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /HauntedModMenu/Buttons/PageButtonTrigger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace HauntedModMenu.Buttons 4 | { 5 | class PageButtonTrigger : ButtonTrigger 6 | { 7 | public Action PageUpdate { get; set; } 8 | 9 | protected override void HandTriggered() 10 | { 11 | PageUpdate(); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /HauntedModMenu/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | D:\Programs\Steam Games\steamapps\common\Gorilla Tag 5 | $(GamePath)\Gorilla Tag_Data\Managed 6 | $(GamePath)\BepInEx\core 7 | $(GamePath)\BepInEx\plugins 8 | 9 | 10 | .\Libs 11 | .\Libs 12 | .\Libs 13 | 0 14 | 15 | 16 | -------------------------------------------------------------------------------- /HauntedModMenu/Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /HauntedModMenu/HarmonyPatches.cs: -------------------------------------------------------------------------------- 1 | using HarmonyLib; 2 | using System; 3 | using System.Reflection; 4 | 5 | namespace HauntedModMenu 6 | { 7 | /// 8 | /// This class handles applying harmony patches to the game. 9 | /// You should not need to modify this class. 10 | /// 11 | public class HarmonyPatches 12 | { 13 | private static Harmony instance; 14 | 15 | public static bool IsPatched { get; private set; } 16 | public const string InstanceId = PluginInfo.GUID; 17 | 18 | internal static void ApplyHarmonyPatches() 19 | { 20 | if (!IsPatched) { 21 | if (instance == null) { 22 | instance = new Harmony(InstanceId); 23 | } 24 | 25 | instance.PatchAll(Assembly.GetExecutingAssembly()); 26 | IsPatched = true; 27 | } 28 | } 29 | 30 | internal static void RemoveHarmonyPatches() 31 | { 32 | if (instance != null && IsPatched) { 33 | instance.UnpatchSelf(); 34 | IsPatched = false; 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /HauntedModMenu/HauntedModMenu.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | $(BepInExAssemblyPath)\0Harmony.dll 14 | 15 | 16 | $(GameAssemblyPath)\Assembly-CSharp.dll 17 | 18 | 19 | $(GameAssemblyPath)\Assembly-CSharp-firstpass.dll 20 | 21 | 22 | $(GameAssemblyPath)\BakeryRuntimeAssembly.dll 23 | 24 | 25 | $(BepInExAssemblyPath)\BepInEx.dll 26 | 27 | 28 | $(BepInExAssemblyPath)\BepInEx.Harmony.dll 29 | 30 | 31 | $(GameAssemblyPath)\Cinemachine.dll 32 | 33 | 34 | $(GameAssemblyPath)\clipper_library.dll 35 | 36 | 37 | $(GameAssemblyPath)\Mono.Security.dll 38 | 39 | 40 | $(GameAssemblyPath)\Oculus.Platform.dll 41 | 42 | 43 | $(GameAssemblyPath)\Oculus.VR.dll 44 | 45 | 46 | $(GameAssemblyPath)\Photon3Unity3D.dll 47 | 48 | 49 | $(GameAssemblyPath)\PhotonRealtime.dll 50 | 51 | 52 | $(GameAssemblyPath)\PhotonUnityNetworking.dll 53 | 54 | 55 | $(GameAssemblyPath)\PhotonUnityNetworking.Utilities.dll 56 | 57 | 58 | $(GameAssemblyPath)\PhotonVoice.dll 59 | 60 | 61 | $(GameAssemblyPath)\PhotonVoice.API.dll 62 | 63 | 64 | $(GameAssemblyPath)\PhotonVoice.PUN.dll 65 | 66 | 67 | $(GameAssemblyPath)\PlayFab.dll 68 | 69 | 70 | $(GameAssemblyPath)\System.EnterpriseServices.dll 71 | 72 | 73 | $(GameAssemblyPath)\System.ServiceModel.Internals.dll 74 | 75 | 76 | $(GameAssemblyPath)\Unity.Animation.Rigging.dll 77 | 78 | 79 | $(GameAssemblyPath)\Unity.Burst.dll 80 | 81 | 82 | $(GameAssemblyPath)\Unity.Burst.Unsafe.dll 83 | 84 | 85 | $(GameAssemblyPath)\Unity.InputSystem.dll 86 | 87 | 88 | $(GameAssemblyPath)\Unity.Mathematics.dll 89 | 90 | 91 | $(GameAssemblyPath)\Unity.Timeline.dll 92 | 93 | 94 | $(GameAssemblyPath)\Unity.XR.Interaction.Toolkit.dll 95 | 96 | 97 | $(GameAssemblyPath)\UnityEngine.dll 98 | 99 | 100 | $(GameAssemblyPath)\UnityEngine.AccessibilityModule.dll 101 | 102 | 103 | $(GameAssemblyPath)\UnityEngine.AIModule.dll 104 | 105 | 106 | $(GameAssemblyPath)\UnityEngine.AndroidJNIModule.dll 107 | 108 | 109 | $(GameAssemblyPath)\UnityEngine.AnimationModule.dll 110 | 111 | 112 | $(GameAssemblyPath)\UnityEngine.ARModule.dll 113 | 114 | 115 | $(GameAssemblyPath)\UnityEngine.AssetBundleModule.dll 116 | 117 | 118 | $(GameAssemblyPath)\UnityEngine.AudioModule.dll 119 | 120 | 121 | $(GameAssemblyPath)\UnityEngine.ClothModule.dll 122 | 123 | 124 | $(GameAssemblyPath)\UnityEngine.ClusterInputModule.dll 125 | 126 | 127 | $(GameAssemblyPath)\UnityEngine.ClusterRendererModule.dll 128 | 129 | 130 | $(GameAssemblyPath)\UnityEngine.CoreModule.dll 131 | 132 | 133 | $(GameAssemblyPath)\UnityEngine.CrashReportingModule.dll 134 | 135 | 136 | $(GameAssemblyPath)\UnityEngine.DirectorModule.dll 137 | 138 | 139 | $(GameAssemblyPath)\UnityEngine.DSPGraphModule.dll 140 | 141 | 142 | $(GameAssemblyPath)\UnityEngine.GameCenterModule.dll 143 | 144 | 145 | $(GameAssemblyPath)\UnityEngine.GridModule.dll 146 | 147 | 148 | $(GameAssemblyPath)\UnityEngine.HotReloadModule.dll 149 | 150 | 151 | $(GameAssemblyPath)\UnityEngine.ImageConversionModule.dll 152 | 153 | 154 | $(GameAssemblyPath)\UnityEngine.IMGUIModule.dll 155 | 156 | 157 | $(GameAssemblyPath)\UnityEngine.InputLegacyModule.dll 158 | 159 | 160 | $(GameAssemblyPath)\UnityEngine.InputModule.dll 161 | 162 | 163 | $(GameAssemblyPath)\UnityEngine.JSONSerializeModule.dll 164 | 165 | 166 | $(GameAssemblyPath)\UnityEngine.LocalizationModule.dll 167 | 168 | 169 | $(GameAssemblyPath)\UnityEngine.ParticleSystemModule.dll 170 | 171 | 172 | $(GameAssemblyPath)\UnityEngine.PerformanceReportingModule.dll 173 | 174 | 175 | $(GameAssemblyPath)\UnityEngine.Physics2DModule.dll 176 | 177 | 178 | $(GameAssemblyPath)\UnityEngine.PhysicsModule.dll 179 | 180 | 181 | $(GameAssemblyPath)\UnityEngine.ProfilerModule.dll 182 | 183 | 184 | $(GameAssemblyPath)\UnityEngine.ScreenCaptureModule.dll 185 | 186 | 187 | $(GameAssemblyPath)\UnityEngine.SharedInternalsModule.dll 188 | 189 | 190 | $(GameAssemblyPath)\UnityEngine.SpatialTracking.dll 191 | 192 | 193 | $(GameAssemblyPath)\UnityEngine.SpriteMaskModule.dll 194 | 195 | 196 | $(GameAssemblyPath)\UnityEngine.SpriteShapeModule.dll 197 | 198 | 199 | $(GameAssemblyPath)\UnityEngine.StreamingModule.dll 200 | 201 | 202 | $(GameAssemblyPath)\UnityEngine.SubstanceModule.dll 203 | 204 | 205 | $(GameAssemblyPath)\UnityEngine.SubsystemsModule.dll 206 | 207 | 208 | $(GameAssemblyPath)\UnityEngine.TerrainModule.dll 209 | 210 | 211 | $(GameAssemblyPath)\UnityEngine.TerrainPhysicsModule.dll 212 | 213 | 214 | $(GameAssemblyPath)\UnityEngine.TextCoreModule.dll 215 | 216 | 217 | $(GameAssemblyPath)\UnityEngine.TextRenderingModule.dll 218 | 219 | 220 | $(GameAssemblyPath)\UnityEngine.TilemapModule.dll 221 | 222 | 223 | $(GameAssemblyPath)\UnityEngine.TLSModule.dll 224 | 225 | 226 | $(GameAssemblyPath)\UnityEngine.UI.dll 227 | 228 | 229 | $(GameAssemblyPath)\UnityEngine.UIElementsModule.dll 230 | 231 | 232 | $(GameAssemblyPath)\UnityEngine.UIModule.dll 233 | 234 | 235 | $(GameAssemblyPath)\UnityEngine.UmbraModule.dll 236 | 237 | 238 | $(GameAssemblyPath)\UnityEngine.UNETModule.dll 239 | 240 | 241 | $(GameAssemblyPath)\UnityEngine.UnityAnalyticsModule.dll 242 | 243 | 244 | $(GameAssemblyPath)\UnityEngine.UnityConnectModule.dll 245 | 246 | 247 | $(GameAssemblyPath)\UnityEngine.UnityTestProtocolModule.dll 248 | 249 | 250 | $(GameAssemblyPath)\UnityEngine.UnityWebRequestAssetBundleModule.dll 251 | 252 | 253 | $(GameAssemblyPath)\UnityEngine.UnityWebRequestAudioModule.dll 254 | 255 | 256 | $(GameAssemblyPath)\UnityEngine.UnityWebRequestModule.dll 257 | 258 | 259 | $(GameAssemblyPath)\UnityEngine.UnityWebRequestTextureModule.dll 260 | 261 | 262 | $(GameAssemblyPath)\UnityEngine.UnityWebRequestWWWModule.dll 263 | 264 | 265 | $(GameAssemblyPath)\UnityEngine.VehiclesModule.dll 266 | 267 | 268 | $(GameAssemblyPath)\UnityEngine.VFXModule.dll 269 | 270 | 271 | $(GameAssemblyPath)\UnityEngine.VideoModule.dll 272 | 273 | 274 | $(GameAssemblyPath)\UnityEngine.VRModule.dll 275 | 276 | 277 | $(GameAssemblyPath)\UnityEngine.WindModule.dll 278 | 279 | 280 | $(GameAssemblyPath)\UnityEngine.XR.LegacyInputHelpers.dll 281 | 282 | 283 | $(GameAssemblyPath)\UnityEngine.XRModule.dll 284 | 285 | 286 | $(PluginsPath)\Utilla\utilla.dll 287 | 288 | 289 | $(GameAssemblyPath)\websocket-sharp.dll 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | -------------------------------------------------------------------------------- /HauntedModMenu/MakeRelease.ps1: -------------------------------------------------------------------------------- 1 | # Needs to be at least that version, or mmm can't read the archive 2 | #Requires -Modules @{ ModuleName="Microsoft.PowerShell.Archive"; ModuleVersion="1.2.3" } 3 | $MyInvocation.MyCommand.Path | Split-Path | Push-Location # Run from this script's directory 4 | $Name = (ls *.csproj).BaseName 5 | dotnet build -c Release 6 | mkdir BepInEx\plugins\$Name 7 | cp bin\Release\netstandard2.0\$Name.dll BepInEx\plugins\$Name\ 8 | Compress-Archive -force .\BepInEx\ $Name-v1.0.1.zip 9 | rmdir .\BepInEx\ -Recurse -------------------------------------------------------------------------------- /HauntedModMenu/Menu/MenuController.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | using HauntedModMenu.Utils; 4 | 5 | namespace HauntedModMenu.Menu 6 | { 7 | class MenuController : Buttons.HandTrigger 8 | { 9 | private bool autoClose; 10 | private float lookSensitivty; 11 | private Collider menuTrigger = null; 12 | private GameObject menu = null; 13 | 14 | private struct PositionOffset 15 | { 16 | public Vector3 leftHandPosition; 17 | public Vector3 rightHandPosition; 18 | public Quaternion leftHandRotation; 19 | public Quaternion rightHandRotation; 20 | } 21 | 22 | private PositionOffset triggerOffset = new PositionOffset { 23 | leftHandPosition = new Vector3(-0.0315f, 0.035f, 0f), 24 | rightHandPosition = new Vector3(0.0315f, 0.035f, 0f), 25 | leftHandRotation = Quaternion.Euler(-30f, 120f, 75f), 26 | rightHandRotation = Quaternion.Euler(-30f, -120f, -75f) 27 | }; 28 | 29 | private PositionOffset menuOffset = new PositionOffset { 30 | leftHandPosition = new Vector3(1.05f, 1.75f, -1.35f), 31 | rightHandPosition = new Vector3(-1.05f, 1.75f, -1.35f), 32 | leftHandRotation = Quaternion.Euler(-25f, 17f, -18.5f), 33 | rightHandRotation = Quaternion.Euler(-25f, -17f, 18.5f) 34 | }; 35 | 36 | protected override void Awake() 37 | { 38 | base.Awake(); 39 | 40 | LoadConfig(); 41 | CreateMenuView(); 42 | SetParent(); 43 | 44 | menuTrigger = this.gameObject.GetComponent(); 45 | if (menuTrigger != null) 46 | menuTrigger.enabled = false; 47 | } 48 | 49 | private void OnEnable() 50 | { 51 | if (leftHandTracker != null) 52 | leftHandTracker.enabled = true; 53 | 54 | if (rightHandTracker != null) 55 | rightHandTracker.enabled = true; 56 | } 57 | 58 | protected override void OnDisable() 59 | { 60 | base.OnDisable(); 61 | 62 | if (leftHandTracker != null) 63 | leftHandTracker.enabled = false; 64 | 65 | if (rightHandTracker != null) 66 | rightHandTracker.enabled = false; 67 | 68 | if (menuTrigger != null) 69 | menuTrigger.enabled = false; 70 | 71 | SaveConfig(); 72 | } 73 | 74 | private void OnDestroy() 75 | { 76 | UnityEngine.Object.Destroy(leftHandTracker); 77 | UnityEngine.Object.Destroy(rightHandTracker); 78 | } 79 | 80 | private void Update() 81 | { 82 | if (RefCache.CameraTransform == null) 83 | return; 84 | 85 | Vector3 handDir = Vector3.Normalize(this.gameObject.transform.position - RefCache.CameraTransform.position); 86 | Vector3 lookDir = RefCache.CameraTransform.forward; 87 | 88 | float dotAngle = Vector3.Dot(handDir, lookDir); 89 | if (dotAngle < lookSensitivty) { 90 | if (autoClose && menu.activeSelf) 91 | HandTriggered(); 92 | 93 | return; 94 | } 95 | 96 | dotAngle = Vector3.Dot(this.gameObject.transform.forward, lookDir); 97 | 98 | if (!menuTrigger.enabled) { 99 | if (dotAngle > lookSensitivty) 100 | menuTrigger.enabled = true; 101 | 102 | } else if (menuTrigger.enabled && dotAngle < 0.3f) { 103 | if (autoClose && menu.activeSelf) 104 | HandTriggered(); 105 | 106 | menuTrigger.enabled = false; 107 | } 108 | } 109 | 110 | private void LoadConfig() 111 | { 112 | autoClose = Config.LoadData("Hand Config", "Auto Close", "whether or not to automatically close the menu when its out of view", true); 113 | leftHand = Config.LoadData("Hand Config", "LeftHand", "which hand the menu is on, true = left hand, false = right hand.", true); 114 | handSensitivity = Config.LoadData("Hand Config", "Hand Speed Sensitivty", "how slow the hand has to be moving to activate the trigger. higher number = more sensitive", 0.8f); 115 | lookSensitivty = Config.LoadData("Hand Config", "Look Sensitivity", "the angle threshold between the camera and the hand need to acivate, value between -1 and 1, -1 = 180 offset (always on), 1 being prefectly inline with the camera. reccomneded 0.7", 0.7f); 116 | 117 | // load mod status 118 | if (RefCache.ModList?.Count > 0) { 119 | foreach (ModInfo modInfo in RefCache.ModList) { 120 | modInfo.Enabled = Config.LoadData("Mod Status", modInfo.Name, "", modInfo.Enabled); 121 | } 122 | } 123 | 124 | // just in case 125 | Config.File?.Save(); 126 | } 127 | 128 | private void SaveConfig() 129 | { 130 | if (RefCache.ModList?.Count < 1) 131 | return; 132 | 133 | foreach(ModInfo modInfo in RefCache.ModList) { 134 | Config.SaveData("Mod Status", modInfo.Name, modInfo.Enabled); 135 | } 136 | } 137 | 138 | private void SetParent() 139 | { 140 | Transform parent = leftHand ? RefCache.LeftHandRig?.transform : RefCache.RightHandRig?.transform; 141 | 142 | if (parent != null) { 143 | Transform myTransform = this.gameObject.transform; 144 | myTransform.SetParent(parent); 145 | 146 | myTransform.localPosition = leftHand ? triggerOffset.leftHandPosition : triggerOffset.rightHandPosition; 147 | myTransform.localRotation = leftHand ? triggerOffset.leftHandRotation : triggerOffset.rightHandRotation; 148 | myTransform.localScale = new Vector3(0.1f, 0.1f, 0.1f); 149 | 150 | if(menu != null) { 151 | menu.transform.localPosition = leftHand ? menuOffset.leftHandPosition : menuOffset.rightHandPosition; 152 | menu.transform.localRotation = leftHand ? menuOffset.leftHandRotation : menuOffset.rightHandRotation; 153 | } 154 | } 155 | } 156 | 157 | public void SetHand(bool lHand) 158 | { 159 | leftHand = lHand; 160 | Config.SaveData("Hand Config", "LeftHand", lHand); 161 | SetParent(); 162 | } 163 | 164 | protected override void HandTriggered() 165 | { 166 | if (menu == null) 167 | return; 168 | 169 | menu.SetActive(!menu.activeSelf); 170 | 171 | if (!menu.activeSelf) 172 | SaveConfig(); 173 | } 174 | 175 | private void CreateMenuView() 176 | { 177 | GameObject go = GameObject.CreatePrimitive(PrimitiveType.Cube); 178 | if (go == null) 179 | return; 180 | 181 | Collider col = go.GetComponent(); 182 | if (col != null) 183 | UnityEngine.Object.Destroy(col); 184 | 185 | go.transform.SetParent(this.gameObject.transform); 186 | go.transform.localScale = new Vector3(1.8f, 3.5f, 0.05f); 187 | 188 | go.AddComponent(); 189 | 190 | go.SetActive(false); 191 | menu = go; 192 | } 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /HauntedModMenu/Menu/MenuView.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Collections.Generic; 3 | 4 | 5 | using UnityEngine; 6 | using UnityEngine.UI; 7 | 8 | using HauntedModMenu.Utils; 9 | 10 | namespace HauntedModMenu.Menu 11 | { 12 | class MenuView : MonoBehaviour 13 | { 14 | private static readonly string emptyName = "<------------------>"; 15 | private static readonly Color enabledColor = new Color(0.4951f, 0.7075f, 0.3771f, 1f); 16 | private static readonly Color disabledColor = new Color(0.8396f, 0.2495f, 0.2495f, 1f); 17 | 18 | private Buttons.PageButtonTrigger nextPageButton = null; 19 | private Buttons.PageButtonTrigger previousPageButton = null; 20 | private Buttons.ModButtonTrigger[] modButtonArray = new Buttons.ModButtonTrigger[5] { null, null, null, null, null }; 21 | 22 | private int page; 23 | private int pageMax; 24 | const int pageSize = 5; 25 | 26 | private void Awake() 27 | { 28 | page = 0; 29 | pageMax = Mathf.FloorToInt(RefCache.ModList.Count / (float)pageSize); 30 | 31 | LoadMenu(); 32 | UpdateButtons(); 33 | } 34 | 35 | private void NextPage() 36 | { 37 | if (page < pageMax) { 38 | page += 1; 39 | UpdateButtons(); 40 | } 41 | } 42 | 43 | private void PreviousPage() 44 | { 45 | if (page > 0) { 46 | page -= 1; 47 | UpdateButtons(); 48 | } 49 | } 50 | 51 | private void UpdateButtons() 52 | { 53 | List currentMods = RefCache.ModList?.Skip(page * pageSize).Take(pageSize).ToList(); 54 | int? modCount = currentMods?.Count; 55 | 56 | for (int index = 0; index < modButtonArray?.Length; index++) { 57 | Buttons.ModButtonTrigger button = modButtonArray[index]; 58 | if (index < modCount) { 59 | 60 | if(button == null) 61 | continue; 62 | 63 | button.ModTarget = currentMods[index]; 64 | button.ButtonText.text = currentMods[index].Name; 65 | 66 | } else { 67 | Debug.Log("setting button to default"); 68 | button.ModTarget = null; 69 | button.ButtonText.text = emptyName; 70 | } 71 | } 72 | 73 | if (page < pageMax) { 74 | nextPageButton.SetColour(true); 75 | 76 | } else { 77 | nextPageButton.SetColour(false); 78 | } 79 | 80 | if (page > 0) { 81 | previousPageButton.SetColour(true); 82 | 83 | } else { 84 | previousPageButton.SetColour(false); 85 | } 86 | } 87 | 88 | #region CREATE_MENU 89 | private void LoadMenu() 90 | { 91 | Debug.Log("loading menu"); 92 | 93 | this.gameObject.GetComponent()?.material?.SetColor("_Color", Config.LoadData("Button Menu Config", "Background Colour", "The colour for the background", Color.black)); 94 | 95 | RectTransform rect = this.gameObject.AddComponent(); 96 | Canvas canvas = this.gameObject.AddComponent(); 97 | 98 | 99 | if (rect != null) { 100 | Debug.Log("setting menu canvas size"); 101 | rect.sizeDelta = new Vector2(1f, 1f); 102 | } 103 | 104 | string[,] textInfo = new string[,] { {"MenuTitle", "Haunted Mod Menu" }, {"PageText", "Pages" } }; 105 | Vector3[] positions = new Vector3[] { new Vector3(0f, 0.435f, -0.51f), new Vector3(0f, -0.4f, -0.51f) }; 106 | 107 | int loopIndex; 108 | GameObject go = null; 109 | Quaternion zeroRotation = Quaternion.identity; 110 | 111 | for (loopIndex = 0; loopIndex < positions?.Length; loopIndex++) { 112 | go = new GameObject(textInfo[loopIndex, 0]); 113 | 114 | if (go != null) { 115 | SetLocal(go.transform, positions[loopIndex], new Vector3(0.0018f, 0.0018f, 0f), zeroRotation); 116 | AddUI(textInfo[loopIndex, 1], go, 50, new Vector2(555f, 60f), Config.LoadData("Button Menu Config", $"{textInfo[loopIndex, 0]} Text Colour", $"The colour for the {textInfo[loopIndex, 1]} text", new Color(0.6132f, 0.6132f, 0.6132f, 1f))); 117 | go = null; 118 | } 119 | } 120 | 121 | GameObject textObject = null; 122 | Vector2 rectSize = new Vector2(450f, 85f); 123 | Vector3 buttonPos = new Vector3(0f, 0.3f, -1f); 124 | Vector3 buttonTextPos = new Vector3(0f, 0f, -0.51f); 125 | Vector3 buttonScale = new Vector3(0.75f, 0.1f, 0.75f); 126 | Vector3 buttonTextScale = new Vector3(0.002208869f, 0.01262004f, 1f); 127 | 128 | for (loopIndex = 0; loopIndex < modButtonArray?.Length; loopIndex++) { 129 | 130 | // create the button 131 | go = CreateButton($"ModButton{loopIndex}"); 132 | SetLocal(go?.transform, buttonPos, buttonScale, zeroRotation); 133 | 134 | // creat the text object 135 | textObject = new GameObject($"ButtonText{loopIndex}"); 136 | 137 | if (textObject != null) { 138 | SetLocal(textObject.transform, buttonTextPos, buttonTextScale, zeroRotation, go?.transform); 139 | AddUI(emptyName, textObject, 45, rectSize, Config.LoadData($"cButtonButton{loopIndex} Config", "Text Colour", "The button text colour", Color.black)); 140 | 141 | // add the trigger script 142 | Buttons.ModButtonTrigger mbt = go?.AddComponent(); 143 | if (mbt != null) { 144 | mbt.EnabledColor = Config.LoadData($"cButtonButton{loopIndex} Config", "Enabled Colour", "The enabled colour for the button", enabledColor); 145 | mbt.DisabledColor = Config.LoadData($"cButtonButton{loopIndex} Config", "Disabled Colour", "The disabled colour for the button", disabledColor); 146 | 147 | mbt.SetColour(false); 148 | modButtonArray[loopIndex] = mbt; 149 | } 150 | } 151 | 152 | // move the button position down 153 | buttonPos.y -= 0.135f; 154 | } 155 | 156 | buttonPos.x = -0.35f; 157 | buttonPos.y = -0.4f; 158 | buttonScale.x = 0.2f; 159 | 160 | textInfo[0, 0] = "Previous"; 161 | textInfo[0, 1] = "<<<<<<<<<<"; 162 | textInfo[1, 0] = "Next"; 163 | textInfo[1, 1] = ">>>>>>>>>>"; 164 | 165 | Buttons.PageButtonTrigger[] pageTriggers = new Buttons.PageButtonTrigger[] { null, null }; 166 | 167 | for (loopIndex = 0; loopIndex < pageTriggers?.Length; loopIndex++) { 168 | go = CreateButton($"{textInfo[loopIndex, 0]}PageButton"); 169 | textObject = new GameObject($"{textInfo[loopIndex, 0]}PageText"); 170 | 171 | AddUI(textInfo[loopIndex, 1], textObject, 50, rectSize, Config.LoadData($"c{textInfo[loopIndex, 0]} Button Config", "Text Colour", "The button text colour", Color.black)); 172 | SetLocal(go?.transform, buttonPos, buttonScale, zeroRotation); 173 | SetLocal(textObject?.transform, buttonTextPos, buttonTextScale, zeroRotation, go?.transform); 174 | 175 | Buttons.PageButtonTrigger pbt = go?.AddComponent(); 176 | if (pbt != null) { 177 | pbt.EnabledColor = Config.LoadData($"c{textInfo[loopIndex, 0]} Button Config", "Enabled Colour", "The enabled colour for the button", enabledColor); 178 | pbt.DisabledColor = Config.LoadData($"c{textInfo[loopIndex, 0]} Button Config", "Disabled Colour", "The disabled colour for the button", disabledColor); 179 | 180 | pbt.SetColour(false); 181 | } 182 | 183 | buttonPos.x *= -1f; 184 | pageTriggers[loopIndex] = pbt; 185 | } 186 | 187 | previousPageButton = pageTriggers[0]; 188 | nextPageButton = pageTriggers[1]; 189 | 190 | if(previousPageButton != null) 191 | previousPageButton.PageUpdate = PreviousPage; 192 | 193 | if (nextPageButton != null) 194 | nextPageButton.PageUpdate = NextPage; 195 | } 196 | 197 | private void AddUI(string text, GameObject go, in int fontSize, in Vector2 rectSize, in Color textColor) 198 | { 199 | if (go == null) 200 | return; 201 | 202 | RectTransform rect = go.AddComponent(); 203 | go.AddComponent(); 204 | Text textUI = go.AddComponent(); 205 | 206 | if (rect != null) 207 | rect.sizeDelta = rectSize; 208 | 209 | if (textUI != null) { 210 | textUI.fontSize = fontSize; 211 | textUI.fontStyle = FontStyle.Normal; 212 | textUI.alignment = TextAnchor.MiddleCenter; 213 | textUI.font = RefCache.CustomFont; 214 | textUI.supportRichText = false; 215 | textUI.color = textColor; 216 | textUI.text = text; 217 | } 218 | } 219 | 220 | private GameObject CreateButton(string name) 221 | { 222 | GameObject go = GameObject.CreatePrimitive(PrimitiveType.Cube); 223 | if (go == null) 224 | return null; 225 | 226 | Collider col = go.GetComponent(); 227 | if (col != null) 228 | col.isTrigger = true; 229 | 230 | go.name = name != null ? name : "HauntedModMenuButton"; 231 | 232 | return go; 233 | } 234 | 235 | 236 | private void SetLocal(Transform goTrans, in Vector3 localPos, in Vector3 localScale, in Quaternion localRotation, Transform parent = null) 237 | { 238 | if (goTrans == null) 239 | return; 240 | 241 | if (parent == null) 242 | parent = this.gameObject.transform; 243 | 244 | goTrans.SetParent(parent); 245 | goTrans.localPosition = localPos; 246 | goTrans.localRotation = localRotation; 247 | goTrans.localScale = localScale; 248 | } 249 | 250 | #endregion 251 | } 252 | } 253 | -------------------------------------------------------------------------------- /HauntedModMenu/Plugin.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.ComponentModel; 4 | 5 | using BepInEx; 6 | using BepInEx.Bootstrap; 7 | using HarmonyLib; 8 | 9 | using UnityEngine; 10 | 11 | using Utilla; 12 | 13 | namespace HauntedModMenu 14 | { 15 | [ModdedGamemode] 16 | [BepInDependency("org.legoandmars.gorillatag.utilla", "1.5.0")] 17 | [BepInPlugin(PluginInfo.GUID, PluginInfo.Name, PluginInfo.Version)] 18 | public class HauntedModMenuPlugin : BaseUnityPlugin 19 | { 20 | private bool inRoom; 21 | private GameObject menuObject = null; 22 | 23 | private void Awake() 24 | { 25 | var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("HauntedModMenu.Resources.font"); 26 | if (stream == null) 27 | return; 28 | 29 | var fontBundle = AssetBundle.LoadFromStream(stream); 30 | if (fontBundle == null) 31 | return; 32 | 33 | Utils.RefCache.CustomFont = fontBundle.LoadAsset("ShortBaby"); 34 | 35 | fontBundle.Unload(false); 36 | } 37 | 38 | private void Start() 39 | { 40 | foreach(BepInEx.PluginInfo plugin in Chainloader.PluginInfos.Values) { 41 | 42 | BaseUnityPlugin modPlugin = plugin.Instance; 43 | Type type = modPlugin.GetType(); 44 | DescriptionAttribute modDescription = type.GetCustomAttribute(); 45 | 46 | if (modDescription == null) 47 | continue; 48 | 49 | if (modDescription.Description.Contains("HauntedModMenu")) { 50 | var enableImp = AccessTools.Method(type, "OnEnable"); 51 | var disableImp = AccessTools.Method(type, "OnDisable"); 52 | 53 | if(enableImp != null && disableImp != null) 54 | Utils.RefCache.ModList.Add(new Utils.ModInfo(modPlugin, plugin.Metadata.Name)); 55 | } 56 | } 57 | 58 | Utilla.Events.GameInitialized += OnGameInitialized; 59 | } 60 | 61 | private void OnEnable() 62 | { 63 | if (menuObject != null && inRoom) 64 | menuObject.SetActive(true); 65 | } 66 | 67 | private void OnDisable() 68 | { 69 | if (menuObject != null) 70 | menuObject.SetActive(false); 71 | } 72 | 73 | private void OnGameInitialized(object sender, EventArgs e) 74 | { 75 | Utils.RefCache.LeftHandFollower = GorillaLocomotion.Player.Instance.leftHandFollower.gameObject; 76 | Utils.RefCache.RightHandFollower = GorillaLocomotion.Player.Instance.rightHandFollower.gameObject; 77 | Utils.RefCache.CameraTransform = GorillaLocomotion.Player.Instance.headCollider.transform; 78 | Utils.RefCache.PlayerTransform = GorillaLocomotion.Player.Instance.turnParent.transform; 79 | 80 | Utils.RefCache.LeftHandRig = GorillaTagger.Instance.offlineVRRig.leftHandTransform.parent.gameObject; 81 | Utils.RefCache.RightHandRig = GorillaTagger.Instance.offlineVRRig.rightHandTransform.parent.gameObject; 82 | } 83 | 84 | /* This attribute tells Utilla to call this method when a modded room is joined */ 85 | [ModdedGamemodeJoin] 86 | public void OnJoin(string gamemode) 87 | { 88 | inRoom = true; 89 | 90 | if (menuObject != null) 91 | return; 92 | 93 | menuObject = CreateTrigger(); 94 | 95 | if (menuObject != null) { 96 | menuObject.AddComponent(); 97 | menuObject.SetActive(this.enabled && this.inRoom); 98 | } 99 | } 100 | 101 | /* This attribute tells Utilla to call this method when a modded room is left */ 102 | [ModdedGamemodeLeave] 103 | public void OnLeave(string gamemode) 104 | { 105 | inRoom = false; 106 | UnityEngine.Object.Destroy(menuObject); 107 | } 108 | 109 | private GameObject CreateTrigger() 110 | { 111 | GameObject go = GameObject.CreatePrimitive(PrimitiveType.Sphere); 112 | if (go == null) 113 | return null; 114 | 115 | Collider col = go.GetComponent(); 116 | if (col != null) 117 | col.isTrigger = true; 118 | 119 | MeshRenderer render = go.GetComponent(); 120 | if (render != null) 121 | UnityEngine.Object.Destroy(render); 122 | 123 | return go; 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /HauntedModMenu/PluginInfo.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace HauntedModMenu 3 | { 4 | /// 5 | /// This class is used to provide information about your mod to BepInEx. 6 | /// 7 | class PluginInfo 8 | { 9 | public const string GUID = "com.ahauntedarmy.gorillatag.hauntedmodmenu"; 10 | public const string Name = "HauntedModMenu"; 11 | public const string Version = "1.0.1"; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /HauntedModMenu/Resources/font: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AHauntedArmy/HauntedModMenu/4b69a298e76accb155e37c38b0c06c939dde1510/HauntedModMenu/Resources/font -------------------------------------------------------------------------------- /HauntedModMenu/TestPlugins.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using BepInEx; 3 | using UnityEngine; 4 | 5 | namespace HauntedModMenu 6 | { 7 | /* 8 | [Description("HauntedModMenu")] 9 | [BepInPlugin("com.HMM.testclass1", "test class1", "0.0.0")] 10 | class TestPlugins1 : BaseUnityPlugin 11 | { 12 | void OnEnable() 13 | { 14 | Debug.Log("testclass1: enabled"); 15 | } 16 | 17 | void OnDisable() { } 18 | } 19 | 20 | [Description("HauntedModMenu")] 21 | [BepInPlugin("com.HMM.testclass12", "test class12", "0.0.0")] 22 | class TestPlugins2 : BaseUnityPlugin 23 | { 24 | void OnEnable() 25 | { 26 | Debug.Log("testclass12: enabled"); 27 | } 28 | 29 | void OnDisable() { } 30 | } 31 | 32 | [Description("HauntedModMenu")] 33 | [BepInPlugin("com.HMM.testclass13", "test class13", "0.0.0")] 34 | class TestPlugins : BaseUnityPlugin 35 | { 36 | void OnEnable() 37 | { 38 | Debug.Log("testclass13: enabled"); 39 | } 40 | 41 | void OnDisable() { } 42 | } 43 | 44 | [Description("HauntedModMenu")] 45 | [BepInPlugin("com.HMM.testclass14", "testclass14", "0.0.0")] 46 | class TestPlugins4 : BaseUnityPlugin 47 | { 48 | void OnEnable() 49 | { 50 | Debug.Log("testclass14: enabled"); 51 | } 52 | 53 | void OnDisable() { } 54 | } 55 | 56 | [Description("HauntedModMenu")] 57 | [BepInPlugin("com.HMM.testclass15", "testclass15", "0.0.0")] 58 | class TestPlugins5 : BaseUnityPlugin 59 | { 60 | void OnEnable() 61 | { 62 | Debug.Log("testclass15: enabled"); 63 | } 64 | 65 | void OnDisable() { } 66 | } 67 | 68 | [Description("HauntedModMenu")] 69 | [BepInPlugin("com.HMM.testclass16", "testclass16", "0.0.0")] 70 | class TestPlugins6 : BaseUnityPlugin 71 | { 72 | void OnEnable() 73 | { 74 | Debug.Log("testclass16: enabled"); 75 | } 76 | 77 | void OnDisable() { } 78 | } 79 | 80 | [Description("HauntedModMenu")] 81 | [BepInPlugin("com.HMM.testclass17", "testclass17", "0.0.0")] 82 | class TestPlugins7 : BaseUnityPlugin 83 | { 84 | void OnEnable() 85 | { 86 | Debug.Log("testclass17: enabled"); 87 | } 88 | 89 | void OnDisable() { } 90 | } 91 | */ 92 | } 93 | -------------------------------------------------------------------------------- /HauntedModMenu/Utils/Cache.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | using UnityEngine; 4 | 5 | namespace HauntedModMenu.Utils 6 | { 7 | // static class to cache references 8 | public static class RefCache 9 | { 10 | public static Font CustomFont { get; set; } = null; 11 | public static List ModList { get; private set; } = new List(); 12 | 13 | // left hand references 14 | public static GameObject LeftHandRig { get; set; } = null; 15 | public static GameObject LeftHandFollower { get; set; } = null; 16 | 17 | // right hand references 18 | public static GameObject RightHandRig { get; set; } = null; 19 | public static GameObject RightHandFollower { get; set; } = null; 20 | 21 | public static Transform CameraTransform { get; set; } = null; 22 | public static Transform PlayerTransform { get; set; } = null; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /HauntedModMenu/Utils/Config.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | using BepInEx; 7 | using BepInEx.Configuration; 8 | 9 | namespace HauntedModMenu.Utils 10 | { 11 | internal static class Config 12 | { 13 | public static ConfigFile File { get; private set; } = new ConfigFile(Path.Combine(Paths.ConfigPath, "HauntedModMenu.cfg"), true); 14 | 15 | public static T LoadData(string tag, string key, string description, T defaultValue) 16 | { 17 | if (File == null) 18 | return defaultValue; 19 | 20 | T data; 21 | ConfigEntry fileData = File.Bind(tag, key, defaultValue, description); 22 | 23 | if (fileData != null) { 24 | data = fileData.Value; 25 | 26 | } else { 27 | data = defaultValue; 28 | } 29 | 30 | return data; 31 | } 32 | 33 | public static void SaveData(string tag, string key, T data) 34 | { 35 | if (File == null) 36 | return; 37 | 38 | ConfigEntry fileData = File.Bind(tag, key, data); 39 | 40 | if (fileData != null) 41 | fileData.Value = data; 42 | 43 | File.Save(); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /HauntedModMenu/Utils/ModInfo.cs: -------------------------------------------------------------------------------- 1 | using BepInEx; 2 | 3 | namespace HauntedModMenu.Utils 4 | { 5 | public class ModInfo 6 | { 7 | private BaseUnityPlugin mod = null; 8 | 9 | public bool Enabled { 10 | get { 11 | if (mod == null) 12 | return false; 13 | 14 | return mod.enabled; 15 | } 16 | 17 | set { 18 | if (mod != null) 19 | mod.enabled = value; 20 | } 21 | } 22 | 23 | public string Name { get; private set; } = null; 24 | 25 | public ModInfo(BaseUnityPlugin plugin, string modName) 26 | { 27 | mod = plugin; 28 | Name = modName; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /HauntedModMenu/Utils/ObjectTracker.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace HauntedModMenu.Utils 4 | { 5 | // this could be usefull in the future 6 | public class ObjectTracker : MonoBehaviour 7 | { 8 | private float speed = 0f; 9 | private Vector3 lastPosition = Vector3.zero; 10 | private Vector3 currentPositon = Vector3.zero; 11 | private Vector3 rawDirection = Vector3.zero; 12 | 13 | public float Speed { 14 | get { return speed > 0f ? speed / Time.deltaTime : 0f; } 15 | } 16 | 17 | public virtual void OnEnable() 18 | { 19 | if (RefCache.PlayerTransform != null) { 20 | lastPosition = this.gameObject.transform.position - RefCache.PlayerTransform.position; 21 | 22 | } else { 23 | lastPosition = this.gameObject.transform.position; 24 | } 25 | } 26 | 27 | public virtual void OnDisable() 28 | { 29 | lastPosition = Vector3.zero; 30 | currentPositon = Vector3.zero; 31 | rawDirection = Vector3.zero; 32 | speed = 0f; 33 | } 34 | 35 | // late update so position changes in Update in other scripts are included 36 | public virtual void LateUpdate() 37 | { 38 | if (RefCache.PlayerTransform != null) { 39 | currentPositon = this.gameObject.transform.position - RefCache.PlayerTransform.position; 40 | 41 | } else { 42 | currentPositon = this.gameObject.transform.position; 43 | } 44 | 45 | rawDirection = currentPositon - lastPosition; 46 | lastPosition = currentPositon; 47 | speed = rawDirection.magnitude; 48 | 49 | // Debug.Log("Object Speed = " + Speed); 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright © 2021 AHauntedArmy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Haunted Mod Menu 2 | ### **Important:** This only works in modded rooms 3 | A PC tool for Gorilla Tag to be able to turn mods on and off without needing to go back to the computer. Tap your palm while looking at it to bring up the menu, tap it again to close it. 4 | 5 | ## Config 6 | There are multiple configuration options available. 7 | - LeftHand: which hand you want the menu to appear on 8 | - Auto Close: if you want the menu to automatically close once its outside the look sensitivity. 9 | - Look Sensitivty: how much your palm needs to be facing your eyes and how much it needs to be in view. 10 | - Speed Sensitivty: how slow the hand needs to be moving to be able to press the buttons or activate the menu. 11 | 12 | the colours for each button, text, and background are also fully customizable. 13 | 14 | ## For Developers 15 | Make sure your mod implements unity's OnEnable and OnDisable in your plugin class, and add the `[Description("")]` attribute from `System.ComponentModel` that contains `"HauntedModMenu"` 16 | ```cs 17 | using System; 18 | using System.ComponentModel; 19 | using BepInEx; 20 | using Utilla; 21 | 22 | namespace ExamplePlugin 23 | { 24 | [Description("HauntedModMenu")] 25 | [BepInDependency("org.legoandmars.gorillatag.utilla", "1.5.0")] 26 | [BepInPlugin("com.ahauntedarmy.gorillatag.exampleplugin", "Example Plugin", "1.0.0")] 27 | public class ExamplePlugin : BaseUnityPlugin 28 | { 29 | bool inAllowedRoom = false; 30 | 31 | void OnEnable() 32 | { 33 | // do enable stuff 34 | } 35 | 36 | void OnDisable() 37 | { 38 | // do disable 39 | } 40 | } 41 | } 42 | ``` 43 | --------------------------------------------------------------------------------