diff --git a/hecl/blender/hecl_blendershell.py b/hecl/blender/hecl_blendershell.py index ee0d2c7bb..7fd425697 100644 --- a/hecl/blender/hecl_blendershell.py +++ b/hecl/blender/hecl_blendershell.py @@ -94,6 +94,7 @@ if ackbytes != b'ACK': quitblender() # slerp branch check +bpy.ops.mesh.primitive_cube_add() orig_rot = bpy.context.object.rotation_mode try: bpy.context.object.rotation_mode = 'QUATERNION_SLERP' diff --git a/hecl/include/hecl/SteamFinder.hpp b/hecl/include/hecl/SteamFinder.hpp new file mode 100644 index 000000000..dc93765dd --- /dev/null +++ b/hecl/include/hecl/SteamFinder.hpp @@ -0,0 +1,14 @@ +#ifndef _HECL_STEAMFINDER_H_ +#define _HECL_STEAMFINDER_H_ + +#include "hecl/SystemChar.hpp" + +namespace hecl +{ + +hecl::SystemString FindCommonSteamApp(const hecl::SystemChar* name); + +} + + +#endif // _HECL_STEAMFINDER_H_ diff --git a/hecl/lib/Blender/BlenderConnection.cpp b/hecl/lib/Blender/BlenderConnection.cpp index 63900df41..2f0e1ee47 100644 --- a/hecl/lib/Blender/BlenderConnection.cpp +++ b/hecl/lib/Blender/BlenderConnection.cpp @@ -15,6 +15,7 @@ #include #include "logvisor/logvisor.hpp" #include "hecl/Blender/BlenderConnection.hpp" +#include "hecl/SteamFinder.hpp" #if _WIN32 #include @@ -231,6 +232,12 @@ void BlenderConnection::_blenderDied() static std::atomic_bool BlenderFirstInit(false); +static bool RegFileExists(const hecl::SystemChar* path) +{ + hecl::Sstat theStat; + return !hecl::Stat(path, &theStat) && S_ISREG(theStat.st_mode); +} + BlenderConnection::BlenderConnection(int verbosityLevel) { BlenderLog.report(logvisor::Info, "Establishing BlenderConnection..."); @@ -299,21 +306,37 @@ BlenderConnection::BlenderConnection(int verbosityLevel) /* User-specified blender path */ #if _WIN32 wchar_t BLENDER_BIN_BUF[2048]; - wchar_t* blenderBin = _wgetenv(L"BLENDER_BIN"); + const wchar_t* blenderBin = _wgetenv(L"BLENDER_BIN"); #else - char* blenderBin = getenv("BLENDER_BIN"); + const char* blenderBin = getenv("BLENDER_BIN"); #endif + /* Steam blender */ + hecl::SystemString steamBlender; + /* Child process of blender */ #if _WIN32 - if (!blenderBin) + if (!blenderBin || !RegFileExists(blenderBin)) { - /* Environment not set; use default */ - wchar_t progFiles[256]; - if (!GetEnvironmentVariableW(L"ProgramFiles", progFiles, 256)) - BlenderLog.report(logvisor::Fatal, L"unable to determine 'Program Files' path"); - _snwprintf(BLENDER_BIN_BUF, 2048, L"%s\\Blender Foundation\\Blender\\blender.exe", progFiles); - blenderBin = BLENDER_BIN_BUF; + /* Environment not set; try steam */ + steamBlender = hecl::FindCommonSteamApp(_S("Blender")); + if (steamBlender.size()) + { + steamBlender += _S("\\blender.exe"); + blenderBin = steamBlender.c_str(); + } + + if (!RegFileExists(blenderBin)) + { + /* No steam; try default */ + wchar_t progFiles[256]; + if (!GetEnvironmentVariableW(L"ProgramFiles", progFiles, 256)) + BlenderLog.report(logvisor::Fatal, L"unable to determine 'Program Files' path"); + _snwprintf(BLENDER_BIN_BUF, 2048, L"%s\\Blender Foundation\\Blender\\blender.exe", progFiles); + blenderBin = BLENDER_BIN_BUF; + if (!RegFileExists(blenderBin)) + BlenderLog.report(logvisor::Fatal, L"unable to find blender.exe"); + } } wchar_t cmdLine[2048]; diff --git a/hecl/lib/CMakeLists.txt b/hecl/lib/CMakeLists.txt index 77f3733fc..b02f5cbb2 100644 --- a/hecl/lib/CMakeLists.txt +++ b/hecl/lib/CMakeLists.txt @@ -47,6 +47,7 @@ add_library(hecl-common ../include/hecl/Backend/HLSL.hpp ../include/hecl/Backend/Metal.hpp ../include/hecl/Blender/BlenderConnection.hpp + ../include/hecl/SteamFinder.hpp ../include/hecl/Frontend.hpp ../include/hecl/Database.hpp ../include/hecl/Runtime.hpp @@ -56,6 +57,7 @@ add_library(hecl-common ../include/hecl/MathExtras.hpp ../include/hecl/UniformBufferPool.hpp ../include/hecl/VertexBufferPool.hpp + SteamFinder.cpp ClientProcess.cpp atdna_HMDLMeta.cpp atdna_Frontend.cpp diff --git a/hecl/lib/SteamFinder.cpp b/hecl/lib/SteamFinder.cpp new file mode 100644 index 000000000..8785ad124 --- /dev/null +++ b/hecl/lib/SteamFinder.cpp @@ -0,0 +1,108 @@ +#include "hecl/SteamFinder.hpp" +#include "hecl/hecl.hpp" +#ifdef WIN32 +#include +#define PATH_SEP L'\\' +#else +#define PATH_SEP '/' +#endif + +namespace hecl +{ + +/* Used to extract alternate steam install directories from libraryfolders.vdf */ +static const std::regex regSteamPath("^\\s+\\\"[0-9]+\\\"\\s+\\\"(.*)\\\"", + std::regex::ECMAScript|std::regex::optimize); + +hecl::SystemString FindCommonSteamApp(const hecl::SystemChar* name) +{ + hecl::SystemString steamInstallDir; + hecl::Sstat theStat; + +#ifdef WIN32 + HKEY hkey; + hecl::SystemChar _steamInstallDir[MAX_PATH] = {0}; + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _S("Software\\Valve\\Steam"), + 0, KEY_QUERY_VALUE, &hkey) != ERROR_SUCCESS) + { + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _S("Software\\Valve\\Steam"), + 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &hkey) != ERROR_SUCCESS) + return {}; + } + + DWORD size = MAX_PATH; + if (RegQueryValueEx(hkey, _S("InstallPath"), nullptr, nullptr, + (LPBYTE)_steamInstallDir, &size) == ERROR_SUCCESS) + steamInstallDir = _steamInstallDir; + RegCloseKey(hkey); + + if (steamInstallDir.empty()) + return {}; + +#elif defined(__APPLE__) + steamInstallDir = getenv("HOME"); + steamInstallDir += "/Library/Application Support/Steam"; + if (hecl::Stat(steamInstallDir.c_str(), &theStat) || !S_ISDIR(theStat.st_mode)) + return {}; + +#else + steamInstallDir = getenv("HOME"); + steamInstallDir += "/.local/share/Steam"; + if (hecl::Stat(steamInstallDir.c_str(), &theStat) || !S_ISDIR(theStat.st_mode)) + { + steamInstallDir = getenv("HOME"); + steamInstallDir += "/.steam/steam"; + if (hecl::Stat(steamInstallDir.c_str(), &theStat) || !S_ISDIR(theStat.st_mode)) + return {}; + } + +#endif + + hecl::SystemString appPath = hecl::SystemString(_S("common")) + PATH_SEP + name; + + /* Try main steam install directory first */ + hecl::SystemString steamAppsMain = steamInstallDir + PATH_SEP + _S("steamapps"); + hecl::SystemString mainAppPath = steamAppsMain + PATH_SEP + appPath; + if (!hecl::Stat(mainAppPath.c_str(), &theStat) && S_ISDIR(theStat.st_mode)) + return mainAppPath; + + /* Iterate alternate steam install dirs */ + hecl::SystemString libraryFoldersVdfPath = steamAppsMain + PATH_SEP + _S("libraryfolders.vdf"); + FILE* fp = hecl::Fopen(libraryFoldersVdfPath.c_str(), _S("r")); + if (!fp) + return {}; + hecl::FSeek(fp, 0, SEEK_END); + int64_t fileLen = hecl::FTell(fp); + if (fileLen <= 0) + { + fclose(fp); + return {}; + } + hecl::FSeek(fp, 0, SEEK_SET); + std::string fileBuf; + fileBuf.resize(fileLen); + if (fread(&fileBuf[0], 1, fileLen, fp) != fileLen) + { + fclose(fp); + return {}; + } + fclose(fp); + + std::smatch dirMatch; + auto begin = fileBuf.cbegin(); + auto end = fileBuf.cend(); + while (std::regex_search(begin, end, dirMatch, regSteamPath)) + { + std::string match = dirMatch[1].str(); + hecl::SystemStringView otherInstallDir(match); + hecl::SystemString otherAppPath = otherInstallDir.sys_str() + PATH_SEP + + _S("steamapps") + PATH_SEP + appPath; + if (!hecl::Stat(otherAppPath.c_str(), &theStat) && S_ISDIR(theStat.st_mode)) + return otherAppPath; + begin = dirMatch.suffix().first; + } + + return {}; +} + +}