diff --git a/build/makefile_base.mak b/build/makefile_base.mak index 3ad4dcc4..99bd42aa 100644 --- a/build/makefile_base.mak +++ b/build/makefile_base.mak @@ -191,6 +191,10 @@ LSTEAMCLIENT64 := ./syn-lsteamclient64/lsteamclient LSTEAMCLIENT_OBJ32 := ./obj-lsteamclient32 LSTEAMCLIENT_OBJ64 := ./obj-lsteamclient64 +STEAMEXE_SRC := $(SRCDIR)/steam_helper +STEAMEXE_OBJ := ./obj-steam +STEAMEXE_SYN := ./syn-steam/steam + WINE := $(SRCDIR)/wine WINE_DST32 := ./dist-wine32 WINE_OBJ32 := ./obj-wine32 @@ -232,6 +236,7 @@ OBJ_DIRS := $(TOOLS_DIR32) $(TOOLS_DIR64) \ $(FFMPEG_OBJ32) $(FFMPEG_OBJ64) \ $(FAUDIO_OBJ32) $(FAUDIO_OBJ64) \ $(LSTEAMCLIENT_OBJ32) $(LSTEAMCLIENT_OBJ64) \ + $(STEAMEXE_OBJ) \ $(WINE_OBJ32) $(WINE_OBJ64) \ $(VRCLIENT_OBJ32) $(VRCLIENT_OBJ64) \ $(DXVK_OBJ32) $(DXVK_OBJ64) \ @@ -337,7 +342,7 @@ $(DIST_FONTS): fonts ALL_TARGETS += dist GOAL_TARGETS += dist -dist: $(DIST_TARGETS) wine vrclient lsteamclient dxvk | $(DST_DIR) +dist: $(DIST_TARGETS) wine vrclient lsteamclient steam dxvk | $(DST_DIR) echo `date '+%s'` `GIT_DIR=$(abspath $(SRCDIR)/.git) git describe --tags` > $(DIST_VERSION) cp $(DIST_VERSION) $(DST_BASE)/ rm -rf $(abspath $(DIST_PREFIX)) && \ @@ -634,6 +639,56 @@ lsteamclient32: $(LSTEAMCLIENT_CONFIGURE_FILES32) | $(WINE_BUILDTOOLS32) $(filte mkdir -pv $(DST_DIR)/lib/wine/ cp -a $(LSTEAMCLIENT_OBJ32)/lsteamclient.dll.so $(DST_DIR)/lib/wine/ +## steam.exe + +$(STEAMEXE_SYN)/.created: $(STEAMEXE_SRC) $(MAKEFILE_DEP) + rm -rf $(STEAMEXE_SYN) + mkdir -p $(STEAMEXE_SYN)/ + cd $(STEAMEXE_SYN)/ && ln -sfv ../../$(STEAMEXE_SRC)/* . + touch $@ + +$(STEAMEXE_SYN): $(STEAMEXE_SYN)/.created + +STEAMEXE_CONFIGURE_FILES := $(STEAMEXE_OBJ)/Makefile + +# 32-bit configure +$(STEAMEXE_CONFIGURE_FILES): SHELL = $(CONTAINER_SHELL32) +$(STEAMEXE_CONFIGURE_FILES): $(STEAMEXE_SYN) $(MAKEFILE_DEP) | $(STEAMEXE_OBJ) $(WINEMAKER) + cd $(dir $@) && \ + $(WINEMAKER) --nosource-fix --nolower-include --nodlls --nomsvcrt --wine32 \ + -I"../$(TOOLS_DIR32)"/include/ \ + -I"../$(TOOLS_DIR32)"/include/wine/ \ + -I"../$(TOOLS_DIR32)"/include/wine/windows/ \ + -I"../$(SRCDIR)"/lsteamclient/steamworks_sdk_142/ \ + -L"../$(TOOLS_DIR32)"/lib/ \ + -L"../$(TOOLS_DIR32)"/lib/wine/ \ + -L"../$(SRCDIR)"/steam_helper/ \ + --guiexe ../$(STEAMEXE_SYN) && \ + cp ../$(STEAMEXE_SYN)/Makefile . && \ + echo >> ./Makefile 'SRCDIR := ../$(STEAMEXE_SYN)' && \ + echo >> ./Makefile 'vpath % $$(SRCDIR)' && \ + echo >> ./Makefile 'steam_exe_LDFLAGS := -m32 -lsteam_api $$(steam_exe_LDFLAGS)' + +## steam goals +STEAMEXE_TARGETS = steam steam_configure + +ALL_TARGETS += $(STEAMEXE_TARGETS) +GOAL_TARGETS_LIBS += steam + +.PHONY: $(STEAMEXE_TARGETS) + +steam_configure: $(STEAMEXE_CONFIGURE_FILES) + +steam: SHELL = $(CONTAINER_SHELL32) +steam: $(STEAMEXE_CONFIGURE_FILES) | $(WINE_BUILDTOOLS32) $(filter $(MAKECMDGOALS),wine64 wine32 wine) + +env PATH="$(abspath $(TOOLS_DIR32))/bin:$(PATH)" LDFLAGS="-m32" CXXFLAGS="-m32 -Wno-attributes $(COMMON_FLAGS) -g" CFLAGS="-m32 $(COMMON_FLAGS) -g" \ + $(MAKE) -C $(STEAMEXE_OBJ) + [ x"$(STRIP)" = x ] || $(STRIP) $(STEAMEXE_OBJ)/steam.exe.so + mkdir -pv $(DST_DIR)/lib/wine/ + cp -a $(STEAMEXE_OBJ)/steam.exe.so $(DST_DIR)/lib/wine/ + cp $(STEAMEXE_SRC)/libsteam_api.so $(DST_DIR)/lib/ + + ## ## wine ## diff --git a/proton b/proton index 2da9755e..d9bab52d 100755 --- a/proton +++ b/proton @@ -609,9 +609,9 @@ def run(): log("Unable to write debug scripts! " + str(sys.exc_info()[1])) if game_arch == ARCH_UNKNOWN: #probably a batch script or something, hopefully start.exe can handle it - run_wine([wine_path, "start", "/unix"] + sys.argv[2:]) + run_wine([wine_path, "steam", "start", "/unix"] + sys.argv[2:]) else: - run_wine([wine_path] + sys.argv[2:]) + run_wine([wine_path, "steam"] + sys.argv[2:]) if sys.version_info[0] == 2: binary_stdout = sys.stdout diff --git a/steam_helper/libsteam_api.so b/steam_helper/libsteam_api.so new file mode 100644 index 00000000..4ee02fe3 Binary files /dev/null and b/steam_helper/libsteam_api.so differ diff --git a/steam_helper/steam.cpp b/steam_helper/steam.cpp new file mode 100644 index 00000000..da8492cc --- /dev/null +++ b/steam_helper/steam.cpp @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2019, Valve Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* This is a stub steam.exe implementation for use inside Proton. It provides + * a small subset of the actual Steam functionality for games that expect + * Windows version of Steam running. */ + +#include + +#pragma push_macro("_WIN32") +#pragma push_macro("__cdecl") +#undef _WIN32 +#undef __cdecl +#include "steam_api.h" +#pragma pop_macro("_WIN32") +#pragma pop_macro("__cdecl") + +#include "wine/unicode.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(steam); + +EXTERN_C HANDLE CDECL __wine_make_process_system(void); + +static void set_active_process_pid(void) +{ + DWORD pid = GetCurrentProcessId(); + RegSetKeyValueA(HKEY_CURRENT_USER, "Software\\Valve\\Steam\\ActiveProcess", "pid", REG_DWORD, &pid, sizeof(pid)); +} + +static DWORD WINAPI create_steam_window(void *arg) +{ + static WNDCLASSEXW wndclass = { sizeof(WNDCLASSEXW) }; + static const WCHAR class_nameW[] = {'v','g','u','i','P','o','p','u','p','W','i','n','d','o','w',0}; + static const WCHAR steamW[] = {'S','t','e','a','m',0}; + MSG msg; + + wndclass.lpfnWndProc = DefWindowProcW; + wndclass.lpszClassName = class_nameW; + + RegisterClassExW(&wndclass); + CreateWindowW(class_nameW, steamW, WS_POPUP, 40, 40, + 400, 300, NULL, NULL, NULL, NULL); + + while (GetMessageW(&msg, NULL, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + return 0; +} + +static void setup_steam_registry(void) +{ + const char *ui_lang; + uint32 appid; + char buf[256]; + HKEY key; + LSTATUS status; + + if (!SteamAPI_Init()) + { + WINE_ERR("SteamAPI_Init failed\n"); + return; + } + + ui_lang = SteamUtils()->GetSteamUILanguage(); + WINE_TRACE("UI language: %s\n", wine_dbgstr_a(ui_lang)); + RegSetKeyValueA(HKEY_CURRENT_USER, "Software\\Valve\\Steam", "language", + REG_SZ, ui_lang, strlen(ui_lang) + 1); + + appid = SteamUtils()->GetAppID(); + WINE_TRACE("appid: %u\n", appid); + sprintf(buf, "Software\\Valve\\Steam\\Apps\\%u", appid); + status = RegCreateKeyA(HKEY_CURRENT_USER, buf, &key); + if (!status) + { + DWORD value; + value = 1; + RegSetKeyValueA(key, NULL, "Installed", REG_DWORD, &value, sizeof(value)); + RegSetKeyValueA(key, NULL, "Running", REG_DWORD, &value, sizeof(value)); + value = 0; + RegSetKeyValueA(key, NULL, "Updating", REG_DWORD, &value, sizeof(value)); + RegCloseKey(key); + } + else WINE_ERR("Could not create key: %u\n", status); + + SteamAPI_Shutdown(); +} + +static int run_process(void) +{ + WCHAR *cmdline = GetCommandLineW(); + STARTUPINFOW si = { sizeof(si) }; + PROCESS_INFORMATION pi; + + /* skip argv[0] */ + if (*cmdline == '"') + { + cmdline = strchrW(cmdline + 1, '"'); + if (cmdline) cmdline++; + } + else + { + cmdline = strchrW(cmdline, ' '); + } + if (!cmdline) + { + WINE_ERR("Invalid command\n"); + return 1; + } + while (*cmdline == ' ') cmdline++; + + WINE_TRACE("Running command %s\n", wine_dbgstr_w(cmdline)); + + if (!CreateProcessW(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) + { + WINE_ERR("Failed to create process %s: %u\n", wine_dbgstr_w(cmdline), GetLastError()); + return 1; + } + + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return 0; +} + +int main(int argc, char *argv[]) +{ + WINE_TRACE("\n"); + + CreateThread(NULL, 0, create_steam_window, NULL, 0, NULL); + + set_active_process_pid(); + setup_steam_registry(); + + if (argc > 1) + { + int ret = run_process(); + if (ret) return ret; + } + + WaitForSingleObject(__wine_make_process_system(), INFINITE); + return 0; +}