DSprtn / GTFO_VR_Plugin

A plugin to add full roomscale Virtual Reality support to your favorite game!
MIT License
143 stars 13 forks source link

Add comms ( bot commands ), fix world UI clipping #40

Closed Nordskog closed 1 year ago

Nordskog commented 1 year ago

What

This PR makes the communication menu ( bot commands ) available in VR by adding the menu itself to the world UI, and adding a new action, OpenAndSelectComms that both opens the menu and navigates to the next item. Navigation can also be accomplished with the weapon prev/next buttons ( base game behavior, no logic added ). Interact is used to select an item, and the existing dismiss button ( Reload ) is used to dismiss the menu.

( Originally OpenAndSelectComms was used to both open the menu and select items, and weaponPrev/Next was used for navigation. This was changed to accommodate people who instead use the radial menu for weapon selection. )

In the process of adding the menu to the WorldSpaceUI, UI element text not rendering through geometry has also been fixed, both for the HUD and nav markers.

VRWorldSpaceUI.cs was heavily refactored to have all the elements share the same code, instead of duplicating basically the same logic for each individual element.

Video of bossing bots around: https://www.youtube.com/watch?v=NCvH0gW9EZg

This PR is accompanied by this pull request to the SteamVR_Standalone_IL2CPP library's GTFO branch

How

Communication menu UI

The Communication Menu works the exact same as the other UI elements, but there are no references to it, so we grab a reference by hooking PUI_CommunicationMenu.Setup()

OpenAndSelectComms action

Aside from adding the new action alongside the existing ones in SteamVR_InputHandler.cs, the action also was also added to the SteamVR_Standalone_IL2CPP library's GTFO branch in this pull request

The input is bound to both ToggleCommunicationMenu and indirectly the MenuScroll (-1f) actions, and we only return true for the relevant action depending on whether the eFocusState is FPS or FPS_CommunicationDialog.

This is complicated by the fact that, as far as I can tell, the game never queries the SelectCommunicationMenu action. Even in the base game I could not get SelectCommunicationMenu to work with an xbox controller, so I'm going to go ahead and say it is broken.

To overcome this we Prefix patch PUI_CommunicationMenu.Update() and check the input ourselves, calling PUI_CommunicationMenu.MoveNext() with PUI_CommunicationMenu.m_highlightedButtonIndex to make it "select" the currently highlighted item. The Prefix skips the function if an item is selected, so it shouldn't break is the devs decide to fix their input at some point.

Since the menu toggle button obviously cannot be held down when the same button is used to navigate, we force eCellSettingID.Gameplay_HoldToShowComsList to false every time the eFocusState changes to FPS.

Finally, PUI_CommunicationMenu.UpdateCmdTripMine, PUI_CommunicationMenu.UpdateCmdSentryGun, and PUI_CommunicationMenu.UpdateButtonsForNode were added to InjectSemanticInteractionTweaks.cs alongside the patches for normal mine and sentry placement, so placement is based on where your hand is rather than where the camera is pointing. PUI_CommunicationMenu.UpdateButtonsForNode is what is used for the final placement, while the two update functions just display the markers.

WorldSpaceUI geometry clipping

It turns out messing with the MeshRenderer of a TextMeshPro has no affect ( now? It must have worked at some point in time ), and you must instead set either TextMeshPro.FontMaterial or TextMeshPro.fontSharedMaterial. As luck would have it, most of the WorldSpaceUI elements share same font material, so in VRWorldSpaceUI.setSharedMaterialShader() we just set the fontSharedMaterial and RenderQueue of an existing CommunicationMenu text object and everything magically renders ontop of everything.

The Compass has its own text material, but conveniently exposes it at PUI_Compass.m_fontMaterial, so we repeat the process there, using VRAssets.TextSphereClip instead of VRAssets.GetTextNoCull(), and all is good.

Nav markers text geometry clipping WorldSpaceUI.PrepareNavMarker() was actually already setting the fontSharedMaterial of all TextMeshPro children, but if you inspect the NavMarkers in-game, it turns out they end up with a completely different material. Not sure if they are completely separate objects or if something changes the material later. Ditto for the sprites?

However, we also set the Sprite shader at InjectNavMarkerWorldSpace.InjectNavMarkerWorldSpriteHack patching NavMarkerComponent.Start(). This patch is what actually does all the work. NavMarkerComponent has an m_text field, and if we modify the fontSharedMaterial of that all our problems are solved. This patch was also changed to modify the sharedMaterial of the Sprite, instead of the Material. This is now the only place the NavMarker materials are modified.

DSprtn commented 1 year ago

Very nice!