Skip to content

Commit

Permalink
CharaStudioVR bepinex config
Browse files Browse the repository at this point in the history
  • Loading branch information
Keelhauled committed Oct 1, 2023
1 parent 3e358f6 commit 9b39af6
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 69 deletions.
1 change: 1 addition & 0 deletions CharaStudioVR/CharaStudioVR.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Settings\CharaStudioContext.cs" />
<Compile Include="Settings\CharaStudioSettingsManager.cs" />
<Compile Include="StudioStandingMode.cs" />
<Compile Include="Controls\GripMenuHandler.cs" />
<Compile Include="Controls\GripMoveStudioNEOV2Tool.cs" />
Expand Down
89 changes: 28 additions & 61 deletions CharaStudioVR/Settings/CharaStudioContext.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.IO;
using System.Xml.Serialization;
using UnityEngine;
using VRGIN.Core;
Expand All @@ -10,41 +9,13 @@ namespace KKS_VR.Settings
[XmlRoot("Context")]
public class CharaStudioContext : IVRManagerContext
{
private static string _contextSavePath = Path.Combine(BepInEx.Paths.ConfigPath, "KKS_CharaStudioVRContext.xml");
private static string _settingsSavePath = Path.Combine(BepInEx.Paths.ConfigPath, "KKS_CharaStudioVRSettings.xml");
private readonly DefaultMaterialPalette _Materials;

private DefaultMaterialPalette _Materials;

public CharaStudioContext()
{
_Materials = new DefaultMaterialPalette();
Settings = CharaStudioSettings.Load(_settingsSavePath);
ConfineMouse = true;
EnforceDefaultGUIMaterials = false;
GUIAlternativeSortingMode = false;
GuiLayer = "Default";
GuiFarClipPlane = 1000f;
GuiNearClipPlane = -1000f;
IgnoreMask = 0;
InvisibleLayer = "Ignore Raycast";
PrimaryColor = Color.cyan;
SimulateCursor = true;
UILayer = "UI";
UILayerMask = LayerMask.GetMask(UILayer);
UnitToMeter = 1f;
NearClipPlane = 0.001f;
PreferredGUI = GUIType.uGUI;
}

public string Version { get; set; }

public float MaxFarClipPlane { get; set; }

public int GuiMaterialRenderQueue { get; set; }
private readonly VRSettings _Settings;

[XmlIgnore] public IMaterialPalette Materials => _Materials;

[XmlIgnore] public VRSettings Settings { get; }
[XmlIgnore] public VRSettings Settings => _Settings;

public bool ConfineMouse { get; set; }

Expand Down Expand Up @@ -76,40 +47,36 @@ public CharaStudioContext()

public GUIType PreferredGUI { get; set; }

public string Version { get; set; }

public float MaxFarClipPlane { get; set; }

public int GuiMaterialRenderQueue { get; set; }

Type IVRManagerContext.VoiceCommandType { get; }

public bool ForceIMGUIOnScreen { get; set; }

public static IVRManagerContext GetContext()

public CharaStudioContext(CharaStudioSettings settings)
{
var path = _contextSavePath;
var xmlSerializer = new XmlSerializer(typeof(CharaStudioContext));
if (File.Exists(path))
{
using var stream = File.OpenRead(path);
try
{
return xmlSerializer.Deserialize(stream) as CharaStudioContext;
}
catch (Exception)
{
VRLog.Error("Failed to deserialize {0} -- using default", path);
}
}

var configurableContext = new CharaStudioContext();
try
{
using var streamWriter = new StreamWriter(path);
streamWriter.BaseStream.SetLength(0L);
xmlSerializer.Serialize(streamWriter, configurableContext);
return configurableContext;
}
catch (Exception)
{
VRLog.Error("Failed to write {0}", path);
return configurableContext;
}
_Materials = new DefaultMaterialPalette();
_Settings = settings;
ConfineMouse = true;
EnforceDefaultGUIMaterials = false;
GUIAlternativeSortingMode = false;
GuiLayer = "Default";
GuiFarClipPlane = 1000f;
GuiNearClipPlane = -1000f;
IgnoreMask = 0;
InvisibleLayer = "Ignore Raycast";
PrimaryColor = Color.cyan;
SimulateCursor = true;
UILayer = "UI";
UILayerMask = LayerMask.GetMask(UILayer);
UnitToMeter = 1f;
NearClipPlane = 0.001f;
PreferredGUI = GUIType.uGUI;
}
}
}
16 changes: 11 additions & 5 deletions CharaStudioVR/Settings/CharaStudioSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,21 @@ public override Shortcuts Shortcuts
protected set => base.Shortcuts = value;
}

public CharaStudioSettings()
public float NearClipPlane
{
IPDScale = 1f;
GrabRotationImmediateMode = false;
get => _NearClipPlane;
set
{
_NearClipPlane = value;
TriggerPropertyChanged("NearClipPlane");
}
}

public static CharaStudioSettings Load(string path)
private float _NearClipPlane;

public CharaStudioSettings()
{
return VRSettings.Load<CharaStudioSettings>(path);
GrabRotationImmediateMode = false;
}
}
}
93 changes: 93 additions & 0 deletions CharaStudioVR/Settings/CharaStudioSettingsManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
using System;
using BepInEx.Configuration;
using KKAPI.Utilities;
using VRGIN.Core;

namespace KKS_VR.Settings
{
/// <summary>
/// Manages configuration and keeps it up to date.
///
/// BepInEx wants us to store the config in a bunch of ConfigEntry objects,
/// but VRGIN wants it stored inside a class inheriting VRSettings. So
/// our plan is:
///
/// * We have both ConfigEntry objects and CharaStudioSettings around.
/// * The ConfigEntry objects are the master copy and the CharaStudioSettings
/// object is a mirror.
/// * CharaStudioSettingsManager is responsible for keeping CharaStudioSettings up to date.
/// * No other parts of code should modify CharaStudioSettings. In fact, there
/// are code paths where VRGIN tries to modify it. We simply attempt
/// to avoid executing those code paths.
/// </summary>
internal class CharaStudioSettingsManager
{
public const string SectionGeneral = "0. General";

/// <summary>
/// Create config entries under the given ConfigFile. Also create a fresh
/// CharaStudioSettings object and arrange that it be synced with the config
/// entries.
/// </summary>
/// <returns>The new CharaStudioSettings object.</returns>
public static CharaStudioSettings Create(ConfigFile config)
{
var settings = new CharaStudioSettings();

var ipdScale = config.Bind(SectionGeneral, "IPD Scale", 1f,
new ConfigDescription(
"Scale of the camera. The higher, the more gigantic the player is.",
new AcceptableValueRange<float>(0.25f, 4f)));
Tie(ipdScale, v => settings.IPDScale = v);

var rumble = config.Bind(SectionGeneral, "Rumble", true,
"Whether or not rumble is activated.");
Tie(rumble, v => settings.Rumble = v);

var rotationMultiplier = config.Bind(SectionGeneral, "Rotation multiplier", 1f,
new ConfigDescription(
"How quickly the the view should rotate when doing so with the controllers.",
new AcceptableValueRange<float>(-4f, 4f),
new ConfigurationManagerAttributes { Order = -1 }));
Tie(rotationMultiplier, v => settings.RotationMultiplier = v);

var logLevel = config.Bind(SectionGeneral, "Log level", VRLog.LogMode.Info,
new ConfigDescription(
"The minimum severity for a message to be logged.",
null,
new ConfigurationManagerAttributes { IsAdvanced = true }));
Tie(logLevel, v => VRLog.Level = v);

var nearClipPlane = config.Bind(SectionGeneral, "Near clip plane", 0.002f,
new ConfigDescription(
"Minimum distance from camera for an object to be shown (causes visual glitches on some maps when set too small)",
new AcceptableValueRange<float>(0.001f, 0.2f)));
Tie(nearClipPlane, v => settings.NearClipPlane = v);

// not used for anything
var lockRotXZ = config.Bind(SectionGeneral, "Lock XZ Axis rotation", true,
new ConfigDescription("Lock XZ Axis (pitch / roll) rotation."));
Tie(lockRotXZ, v => settings.LockRotXZ = v);

var maxVoiceDistance = config.Bind(SectionGeneral, "Max Voice distance", 300f,
new ConfigDescription(
"Max Voice distance (in unit. 300 = 30m in real (HS2 uses 10 unit = 1m scale).",
new AcceptableValueRange<float>(100f, 600f)));
Tie(maxVoiceDistance, v => settings.MaxVoiceDistance = v);

var minVoiceDistance = config.Bind(SectionGeneral, "Min Voice distance", 7f,
new ConfigDescription(
"Min Voice distance (in unit. 7 = 70 cm in real (HS2 uses 10 unit = 1m scale).",
new AcceptableValueRange<float>(1f, 70f)));
Tie(minVoiceDistance, v => settings.MinVoiceDistance = v);

return settings;
}

private static void Tie<T>(ConfigEntry<T> entry, Action<T> set)
{
set(entry.Value);
entry.SettingChanged += (_, _1) => set(entry.Value);
}
}
}
16 changes: 13 additions & 3 deletions CharaStudioVR/VRPlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,12 @@ public void Awake()
{
BepInExVrLogBackend.ApplyYourself();
OpenVRHelperTempfixHook.Patch();
StartCoroutine(LoadDevice());
var settings = CharaStudioSettingsManager.Create(Config);
StartCoroutine(LoadDevice(settings));
}
}

private IEnumerator LoadDevice()
private IEnumerator LoadDevice(CharaStudioSettings settings)
{
// For some reason using Scene.LoadSceneName instead of SceneManager will break the background color, probably some timing issue
yield return new WaitUntil(() => Manager.Scene.initialized && SceneManager.GetActiveScene().name == "Studio");
Expand Down Expand Up @@ -110,7 +111,11 @@ private IEnumerator LoadDevice()

TopmostToolIcons.Patch();

VRManager.Create<KKSCharaStudioInterpreter>(CharaStudioContext.GetContext());
VRManager.Create<KKSCharaStudioInterpreter>(new CharaStudioContext(settings));

// VRGIN doesn't update the near clip plane until a first "main" camera is created, so we set it here.
UpdateNearClipPlane(settings);
settings.AddListener("NearClipPlane", (_, _1) => UpdateNearClipPlane(settings));

VR.Manager.SetMode<StudioStandingMode>();

Expand All @@ -129,6 +134,11 @@ private IEnumerator LoadDevice()
base.Logger.LogInfo("Finished loading into VR mode!");
}

private void UpdateNearClipPlane(CharaStudioSettings settings)
{
VR.Camera.gameObject.GetComponent<UnityEngine.Camera>().nearClipPlane = settings.NearClipPlane;
}

private static class NativeMethods
{
[DllImport("user32.dll")]
Expand Down

0 comments on commit 9b39af6

Please sign in to comment.