mirror of
https://github.com/vrcx-team/VRCX.git
synced 2026-04-06 00:32:02 +02:00
* init * SQLite changes * Move html folder, edit build scripts * AppApi interface * Build flags * AppApi inheritance * Finishing touches * Merge upstream changes * Test CI * Fix class inits * Rename AppApi * Merge upstream changes * Fix SQLiteLegacy on Linux, Add Linux interop, build tools * Linux specific localisation strings * Make it run * Bring back most of Linux functionality * Clean up * Fix TTS voices * Fix UI var * Changes * Electron minimise to tray * Remove separate toggle for WlxOverlay * Fixes * Touchups * Move csproj * Window zoom, Desktop Notifications, VR check on Linux * Fix desktop notifications, VR check spam * Fix building on Linux * Clean up * Fix WebApi headers * Rewrite VRCX updater * Clean up * Linux updater * Add Linux to build action * init * SQLite changes * Move html folder, edit build scripts * AppApi interface * Build flags * AppApi inheritance * Finishing touches * Merge upstream changes * Test CI * Fix class inits * Rename AppApi * Merge upstream changes * Fix SQLiteLegacy on Linux, Add Linux interop, build tools * Linux specific localisation strings * Make it run * Bring back most of Linux functionality * Clean up * Fix TTS voices * Changes * Electron minimise to tray * Remove separate toggle for WlxOverlay * Fixes * Touchups * Move csproj * Window zoom, Desktop Notifications, VR check on Linux * Fix desktop notifications, VR check spam * Fix building on Linux * Clean up * Fix WebApi headers * Rewrite VRCX updater * Clean up * Linux updater * Add Linux to build action * Test updater * Rebase and handle merge conflicts * Fix Linux updater * Fix Linux app restart * Fix friend order * Handle AppImageInstaller, show an install message on Linux * Updates to the AppImage installer * Fix Linux updater, fix set version, check for .NET, copy wine prefix * Handle random errors * Rotate tall prints * try fix Linux restart bug * Final --------- Co-authored-by: rs189 <35667100+rs189@users.noreply.github.com>
279 lines
10 KiB
C#
279 lines
10 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
using System.Text.Json;
|
|
using System.Threading;
|
|
using System.Windows.Forms;
|
|
using Microsoft.Win32;
|
|
|
|
namespace VRCX
|
|
{
|
|
public partial class AppApiCef
|
|
{
|
|
[DllImport("advapi32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
|
|
private static extern uint RegSetValueEx(
|
|
UIntPtr hKey,
|
|
[MarshalAs(UnmanagedType.LPStr)] string lpValueName,
|
|
int Reserved,
|
|
RegistryValueKind dwType,
|
|
byte[] lpData,
|
|
int cbData);
|
|
|
|
[DllImport("advapi32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
|
|
private static extern int RegOpenKeyEx(
|
|
UIntPtr hKey,
|
|
string subKey,
|
|
int ulOptions,
|
|
int samDesired,
|
|
out UIntPtr hkResult);
|
|
|
|
[DllImport("advapi32.dll")]
|
|
private static extern int RegCloseKey(UIntPtr hKey);
|
|
|
|
private string AddHashToKeyName(string key)
|
|
{
|
|
// https://discussions.unity.com/t/playerprefs-changing-the-name-of-keys/30332/4
|
|
// VRC_GROUP_ORDER_usr_032383a7-748c-4fb2-94e4-bcb928e5de6b_h2810492971
|
|
uint hash = 5381;
|
|
foreach (var c in key)
|
|
hash = (hash * 33) ^ c;
|
|
return key + "_h" + hash;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves the value of the specified key from the VRChat group in the windows registry.
|
|
/// </summary>
|
|
/// <param name="key">The name of the key to retrieve.</param>
|
|
/// <returns>The value of the specified key, or null if the key does not exist.</returns>
|
|
public override object GetVRChatRegistryKey(string key)
|
|
{
|
|
var keyName = AddHashToKeyName(key);
|
|
using var regKey = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\VRChat\VRChat");
|
|
var data = regKey?.GetValue(keyName);
|
|
if (data == null)
|
|
return null;
|
|
|
|
var type = regKey.GetValueKind(keyName);
|
|
switch (type)
|
|
{
|
|
case RegistryValueKind.Binary:
|
|
return Encoding.ASCII.GetString((byte[])data);
|
|
|
|
case RegistryValueKind.DWord:
|
|
if (data.GetType() != typeof(long))
|
|
return data;
|
|
|
|
long.TryParse(data.ToString(), out var longValue);
|
|
var bytes = BitConverter.GetBytes(longValue);
|
|
var doubleValue = BitConverter.ToDouble(bytes, 0);
|
|
return doubleValue;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public override string GetVRChatRegistryKeyString(string key)
|
|
{
|
|
// for electron
|
|
return GetVRChatRegistryKey(key)?.ToString();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the value of the specified key in the VRChat group in the windows registry.
|
|
/// </summary>
|
|
/// <param name="key">The name of the key to set.</param>
|
|
/// <param name="value">The value to set for the specified key.</param>
|
|
/// <param name="typeInt">The RegistryValueKind type.</param>
|
|
/// <returns>True if the key was successfully set, false otherwise.</returns>
|
|
public override bool SetVRChatRegistryKey(string key, object value, int typeInt)
|
|
{
|
|
var type = (RegistryValueKind)typeInt;
|
|
var keyName = AddHashToKeyName(key);
|
|
using var regKey = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\VRChat\VRChat", true);
|
|
if (regKey == null)
|
|
return false;
|
|
|
|
object setValue = null;
|
|
switch (type)
|
|
{
|
|
case RegistryValueKind.Binary:
|
|
setValue = Encoding.ASCII.GetBytes(value.ToString());
|
|
break;
|
|
|
|
case RegistryValueKind.DWord:
|
|
setValue = value;
|
|
break;
|
|
}
|
|
|
|
if (setValue == null)
|
|
return false;
|
|
|
|
regKey.SetValue(keyName, setValue, type);
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the value of the specified key in the VRChat group in the windows registry.
|
|
/// </summary>
|
|
/// <param name="key">The name of the key to set.</param>
|
|
/// <param name="value">The value to set for the specified key.</param>
|
|
public override void SetVRChatRegistryKey(string key, byte[] value)
|
|
{
|
|
var keyName = AddHashToKeyName(key);
|
|
var hKey = (UIntPtr)0x80000001; // HKEY_LOCAL_MACHINE
|
|
const int keyWrite = 0x20006;
|
|
const string keyFolder = @"SOFTWARE\VRChat\VRChat";
|
|
var openKeyResult = RegOpenKeyEx(hKey, keyFolder, 0, keyWrite, out var folderPointer);
|
|
if (openKeyResult != 0)
|
|
throw new Exception("Error opening registry key. Error code: " + openKeyResult);
|
|
|
|
var setKeyResult = RegSetValueEx(folderPointer, keyName, 0, RegistryValueKind.DWord, value, value.Length);
|
|
if (setKeyResult != 0)
|
|
throw new Exception("Error setting registry value. Error code: " + setKeyResult);
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
public override Dictionary<string, Dictionary<string, object>> GetVRChatRegistry()
|
|
{
|
|
var output = new Dictionary<string, Dictionary<string, object>>();
|
|
using var regKey = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\VRChat\VRChat");
|
|
if (regKey == null)
|
|
throw new Exception("Nothing to backup.");
|
|
|
|
var keys = regKey.GetValueNames();
|
|
|
|
Span<long> spanLong = stackalloc long[1];
|
|
Span<double> doubleSpan = MemoryMarshal.Cast<long, double>(spanLong);
|
|
|
|
foreach (var key in keys)
|
|
{
|
|
var data = regKey.GetValue(key);
|
|
var index = key.LastIndexOf("_h", StringComparison.Ordinal);
|
|
if (index <= 0)
|
|
continue;
|
|
|
|
var keyName = key.Substring(0, index);
|
|
if (data == null)
|
|
continue;
|
|
|
|
var type = regKey.GetValueKind(key);
|
|
switch (type)
|
|
{
|
|
case RegistryValueKind.Binary:
|
|
var binDict = new Dictionary<string, object>
|
|
{
|
|
{ "data", Encoding.ASCII.GetString((byte[])data) },
|
|
{ "type", type }
|
|
};
|
|
output.Add(keyName, binDict);
|
|
break;
|
|
|
|
case RegistryValueKind.DWord:
|
|
if (data.GetType() != typeof(long))
|
|
{
|
|
var dwordDict = new Dictionary<string, object>
|
|
{
|
|
{ "data", data },
|
|
{ "type", type }
|
|
};
|
|
output.Add(keyName, dwordDict);
|
|
break;
|
|
}
|
|
|
|
spanLong[0] = (long)data;
|
|
var doubleValue = doubleSpan[0];
|
|
var floatDict = new Dictionary<string, object>
|
|
{
|
|
{ "data", doubleValue },
|
|
{ "type", 100 } // it's special
|
|
};
|
|
output.Add(keyName, floatDict);
|
|
break;
|
|
|
|
default:
|
|
Debug.WriteLine($"Unknown registry value kind: {type}");
|
|
break;
|
|
}
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
public override void SetVRChatRegistry(string json)
|
|
{
|
|
CreateVRChatRegistryFolder();
|
|
Span<double> spanDouble = stackalloc double[1];
|
|
var dict = JsonSerializer.Deserialize<Dictionary<string, Dictionary<string, object>>>(json);
|
|
foreach (var item in dict)
|
|
{
|
|
var data = (JsonElement)item.Value["data"];
|
|
if (!int.TryParse(item.Value["type"].ToString(), out var type))
|
|
throw new Exception("Unknown type: " + item.Value["type"]);
|
|
|
|
if (data.ValueKind == JsonValueKind.Number)
|
|
{
|
|
if (type == 100)
|
|
{
|
|
// fun handling of double to long to byte array
|
|
spanDouble[0] = data.Deserialize<double>();
|
|
var valueLong = MemoryMarshal.Cast<double, long>(spanDouble)[0];
|
|
const int dataLength = sizeof(long);
|
|
var dataBytes = new byte[dataLength];
|
|
Buffer.BlockCopy(BitConverter.GetBytes(valueLong), 0, dataBytes, 0, dataLength);
|
|
SetVRChatRegistryKey(item.Key, dataBytes);
|
|
continue;
|
|
}
|
|
|
|
if (int.TryParse(data.ToString(), out var intValue))
|
|
{
|
|
SetVRChatRegistryKey(item.Key, intValue, type);
|
|
continue;
|
|
}
|
|
|
|
throw new Exception("Unknown number type: " + item.Key);
|
|
}
|
|
|
|
SetVRChatRegistryKey(item.Key, data, type);
|
|
}
|
|
}
|
|
|
|
public override bool HasVRChatRegistryFolder()
|
|
{
|
|
using var regKey = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\VRChat\VRChat");
|
|
return regKey != null;
|
|
}
|
|
|
|
private void CreateVRChatRegistryFolder()
|
|
{
|
|
if (HasVRChatRegistryFolder())
|
|
return;
|
|
|
|
using var key = Registry.CurrentUser.CreateSubKey(@"SOFTWARE\VRChat\VRChat");
|
|
if (key == null)
|
|
throw new Exception("Error creating registry key.");
|
|
}
|
|
|
|
public override void DeleteVRChatRegistryFolder()
|
|
{
|
|
using var regKey = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\VRChat\VRChat");
|
|
if (regKey == null)
|
|
return;
|
|
|
|
Registry.CurrentUser.DeleteSubKeyTree(@"SOFTWARE\VRChat\VRChat");
|
|
}
|
|
|
|
public override string ReadVrcRegJsonFile(string filepath)
|
|
{
|
|
if (!File.Exists(filepath))
|
|
return string.Empty;
|
|
|
|
var json = File.ReadAllText(filepath);
|
|
return json;
|
|
}
|
|
}
|
|
} |