Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/ValveSoftware/Proton.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Eikum <aeikum@codeweavers.com>2020-02-26 19:50:10 +0300
committerAndrew Eikum <aeikum@codeweavers.com>2020-03-09 18:03:54 +0300
commit349df9c436c2d27e4193cec9f41b16a4b5b60a5c (patch)
treecb5d6eb602cc71119a9dc06497cd02618982c4f4 /steam_helper
parente1c5da52c6d8e9251087525f0ae47a4d919d296a (diff)
steam_helper: Set up VR paths in steam.exe, not proton
This speeds up game launch times.
Diffstat (limited to 'steam_helper')
-rw-r--r--steam_helper/steam.cpp293
1 files changed, 292 insertions, 1 deletions
diff --git a/steam_helper/steam.cpp b/steam_helper/steam.cpp
index 9dcc8914..21134edd 100644
--- a/steam_helper/steam.cpp
+++ b/steam_helper/steam.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, Valve Corporation
+ * Copyright (c) 2015, 2019, 2020 Valve Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
@@ -33,6 +33,7 @@
* Windows version of Steam running. */
#include <windows.h>
+#include <shlobj.h>
#include <string.h>
#include <stdio.h>
@@ -46,6 +47,8 @@
#include "wine/debug.h"
+#include "json/json.h"
+
WINE_DEFAULT_DEBUG_CHANNEL(steam);
EXTERN_C HANDLE CDECL __wine_make_process_system(void);
@@ -117,6 +120,292 @@ static void setup_steam_registry(void)
SteamAPI_Shutdown();
}
+static std::string get_linux_vr_path(void)
+{
+ const char *e;
+
+ e = getenv("VR_PATHREG_OVERRIDE");
+ if(e && *e)
+ return e;
+
+ e = getenv("XDG_CONFIG_HOME");
+
+ if(!e || !*e)
+ e = getenv("HOME");
+
+ if(!e || !*e)
+ return "";
+
+ return std::string(e) + "/.config/openvr/openvrpaths.vrpath";
+}
+
+static bool get_windows_vr_path(WCHAR *out_path, bool create)
+{
+ if(FAILED(SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE,
+ NULL, 0, out_path)))
+ return false;
+
+ lstrcatW(out_path, L"\\openvr");
+
+ if(create)
+ CreateDirectoryW(out_path, NULL);
+
+ lstrcatW(out_path, L"\\openvrpaths.vrpath");
+
+ return true;
+}
+
+static WCHAR *str_to_wchar(const std::string &str)
+{
+ DWORD sz = MultiByteToWideChar(CP_UNIXCP, 0, str.c_str(), -1, NULL, 0);
+ if(!sz)
+ return NULL;
+
+ WCHAR *ret = (WCHAR *)HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * sz);
+ if(!ret)
+ return NULL;
+
+ sz = MultiByteToWideChar(CP_UNIXCP, 0, str.c_str(), -1, ret, sz);
+ if(!sz)
+ {
+ HeapFree(GetProcessHeap(), 0, ret);
+ return NULL;
+ }
+
+ return ret;
+}
+
+static std::string read_text_file(const WCHAR *filename)
+{
+ HANDLE ifile = CreateFileW(filename, GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if(ifile == INVALID_HANDLE_VALUE)
+ return "";
+
+ LARGE_INTEGER size;
+
+ if(!GetFileSizeEx(ifile, &size))
+ {
+ CloseHandle(ifile);
+ return "";
+ }
+
+ char *buf = (char *)HeapAlloc(GetProcessHeap(), 0, size.u.LowPart);
+ if(!buf)
+ {
+ CloseHandle(ifile);
+ return "";
+ }
+
+ DWORD readed;
+
+ if(!ReadFile(ifile, buf, size.u.LowPart, &readed, NULL))
+ {
+ HeapFree(GetProcessHeap(), 0, buf);
+ CloseHandle(ifile);
+ return "";
+ }
+
+ CloseHandle(ifile);
+
+ DWORD outsize = 1;
+ for(DWORD i = 1; i < readed; ++i)
+ {
+ if(buf[i] == '\n' && buf[i - 1] == '\r') // CRLF
+ buf[outsize - 1] = '\n';
+ else
+ buf[outsize++] = buf[i];
+ }
+
+ std::string ret(buf, outsize);
+
+ HeapFree(GetProcessHeap(), 0, buf);
+
+ return ret;
+}
+
+static bool write_string_to_file(const WCHAR *filename, const std::string &contents)
+{
+ HANDLE ofile = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ if(ofile == INVALID_HANDLE_VALUE)
+ return false;
+
+ DWORD written;
+
+ if(!WriteFile(ofile, contents.data(), (DWORD)contents.length(), &written, NULL))
+ {
+ CloseHandle(ofile);
+ return false;
+ }
+
+ CloseHandle(ofile);
+
+ return true;
+}
+
+static bool convert_path_to_win(std::string &s)
+{
+ WCHAR *path = wine_get_dos_file_name(s.c_str());
+ if(!path)
+ return false;
+
+ DWORD sz = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL);
+ if(!sz)
+ {
+ HeapFree(GetProcessHeap(), 0, path);
+ return false;
+ }
+
+ char *pathUTF8 = (char *)HeapAlloc(GetProcessHeap(), 0, sz);
+ if(!pathUTF8)
+ {
+ HeapFree(GetProcessHeap(), 0, path);
+ return false;
+ }
+
+ sz = WideCharToMultiByte(CP_UTF8, 0, path, -1, pathUTF8, sz, NULL, NULL);
+ if(!sz)
+ {
+ HeapFree(GetProcessHeap(), 0, pathUTF8);
+ HeapFree(GetProcessHeap(), 0, path);
+ return false;
+ }
+
+ s = pathUTF8;
+
+ HeapFree(GetProcessHeap(), 0, pathUTF8);
+ HeapFree(GetProcessHeap(), 0, path);
+
+ return true;
+}
+
+static void convert_json_array_paths(Json::Value &arr)
+{
+ for(uint32_t i = 0; i < arr.size(); ++i)
+ {
+ std::string path(arr[i].asString());
+ if(convert_path_to_win(path))
+ arr[i] = path;
+ }
+}
+
+static void convert_environment_path(const char *nameA, const WCHAR *nameW)
+{
+ /* get linux-side variable */
+ const char *e = getenv(nameA);
+ if(!e || !*e)
+ return;
+
+ /* convert to win and set */
+ WCHAR *path = wine_get_dos_file_name(e);
+ if(!path)
+ return;
+
+ SetEnvironmentVariableW(nameW, path);
+
+ HeapFree(GetProcessHeap(), 0, path);
+}
+
+static void set_env_from_unix(const WCHAR *name, const std::string &val)
+{
+ WCHAR valW[MAX_PATH];
+ DWORD sz;
+
+ sz = MultiByteToWideChar(CP_UTF8, 0, val.c_str(), -1, valW, MAX_PATH);
+ if(!sz)
+ {
+ WINE_WARN("Invalid utf8 seq in vr runtime key\n");
+ return;
+ }
+
+ SetEnvironmentVariableW(name, valW);
+}
+
+static bool convert_linux_vrpaths(void)
+{
+ /* read in linux vrpaths */
+ std::string linux_vrpaths = get_linux_vr_path();
+ if(linux_vrpaths.empty())
+ {
+ WINE_TRACE("Couldn't get openvr vrpaths path\n");
+ return false;
+ }
+
+ WCHAR *linux_vrpathsW = str_to_wchar(linux_vrpaths);
+ if(!linux_vrpathsW)
+ return false;
+
+ std::string contents = read_text_file(linux_vrpathsW);
+ HeapFree(GetProcessHeap(), 0, linux_vrpathsW);
+ if(contents.empty())
+ {
+ WINE_TRACE("openvr vrpaths is empty\n");
+ return false;
+ }
+
+ Json::Value root;
+ Json::Reader reader;
+
+ if(!reader.parse(contents, root))
+ {
+ WINE_WARN("Invalid openvr vrpaths JSON\n");
+ return false;
+ }
+
+ /* pass original runtime path into Wine */
+ if(root.isMember("runtime") && root["runtime"].isArray() && root["runtime"].size() > 0)
+ {
+ set_env_from_unix(L"PROTON_VR_RUNTIME", root["runtime"][0].asString());
+ }
+
+ /* set hard-coded paths */
+ root["runtime"] = Json::Value(Json::ValueType::arrayValue);
+ root["runtime"][0] = "C:\\vrclient\\";
+ root["runtime"][1] = "C:\\vrclient";
+
+ /* map linux paths into windows filesystem */
+ if(root.isMember("config") && root["config"].isArray())
+ convert_json_array_paths(root["config"]);
+
+ if(root.isMember("log") && root["log"].isArray())
+ convert_json_array_paths(root["log"]);
+
+ /* external_drivers is currently unsupported in Proton */
+ root["external_drivers"] = Json::Value(Json::ValueType::nullValue);
+
+ /* write out windows vrpaths */
+ SetEnvironmentVariableW(L"VR_PATHREG_OVERRIDE", NULL);
+ SetEnvironmentVariableW(L"VR_OVERRIDE", NULL);
+ convert_environment_path("VR_CONFIG_PATH", L"VR_CONFIG_PATH");
+ convert_environment_path("VR_LOG_PATH", L"VR_LOG_PATH");
+ Json::StyledWriter writer;
+
+ WCHAR windows_vrpaths[MAX_PATH];
+ if(!get_windows_vr_path(windows_vrpaths, true))
+ return false;
+
+ contents = writer.write(root);
+
+ write_string_to_file(windows_vrpaths, contents);
+
+ return true;
+}
+
+static void setup_vrpaths(void)
+{
+ if(!convert_linux_vrpaths())
+ {
+ /* delete the windows file only if the linux conversion fails */
+ WCHAR windows_vrpaths[MAX_PATH];
+ if(get_windows_vr_path(windows_vrpaths, false))
+ {
+ DeleteFileW(windows_vrpaths);
+ }
+ }
+}
+
static WCHAR *strchrW(WCHAR *h, WCHAR n)
{
do
@@ -293,6 +582,8 @@ int main(int argc, char *argv[])
{
HANDLE child;
+ setup_vrpaths();
+
child = run_process();
if (child == INVALID_HANDLE_VALUE)