Ver Fonte

linux: patches to allow the game to run under wine/proton

totaltaxamount há 3 semanas atrás
pai
commit
874ed8182e

+ 14 - 0
Sunrise/src/client/graphics/wine_compat.cpp

@@ -0,0 +1,14 @@
+#include "wine_compat.h"
+
+#include "windows.h"
+
+namespace sunrise::client::graphics {
+
+// Helper function to let wine know that we will be using the display
+void initialize_wine_display() {
+    HDC hdc = GetDC(NULL);
+    if (hdc) {
+        ReleaseDC(NULL, hdc);
+    }
+}
+} // namespace sunrise::client::graphics

+ 5 - 0
Sunrise/src/client/graphics/wine_compat.h

@@ -0,0 +1,5 @@
+#pragma once
+
+namespace sunrise::client::graphics {
+void initialize_wine_display();
+}

+ 36 - 4
Sunrise/src/client/hooks/egress/lifecycle/egress_guard_exports.cpp

@@ -1,7 +1,10 @@
+#include <string>
+
 #include "../dns/egress_dns_replacements.h"
 #include "../dns/egress_dns_replacements.h"
 #include "../extensions/egress_extension_replacements.h"
 #include "../extensions/egress_extension_replacements.h"
 #include "../resolver/replacements.h"
 #include "../resolver/replacements.h"
 #include "../winsock/replacements.h"
 #include "../winsock/replacements.h"
+#include "core/runtime/host_environment.h"
 #include "internal.h"
 #include "internal.h"
 
 
 namespace sunrise::client::hooks::egress::lifecycle {
 namespace sunrise::client::hooks::egress::lifecycle {
@@ -21,12 +24,28 @@ export_definition(ModuleSlot module, const char* name, Function replacement) noe
 
 
 } // namespace
 } // namespace
 
 
+// Dummy functions, these are not exported by wine so we provide at least 5 bytes for detours to
+// copy
+__declspec(noinline) int WSAAPI Dummy_WSAConnectByList() {
+    volatile int dummy = 0;
+    dummy += 1;
+    return -1; // SOCKET_ERROR
+}
+
+__declspec(noinline) int WSAAPI Dummy_GetAddrInfoExA() {
+    volatile int dummy = 0;
+    dummy += 1;
+    return 11001; // WSAHOST_NOT_FOUND
+}
+
 /** Finds the whole Windows SDK egress surface for one atomic Detours batch. */
 /** Finds the whole Windows SDK egress surface for one atomic Detours batch. */
 bool resolve_specs(std::span<hooking::detour::Spec, kHookCount> specs,
 bool resolve_specs(std::span<hooking::detour::Spec, kHookCount> specs,
                    std::span<const char*, kHookCount> names,
                    std::span<const char*, kHookCount> names,
                    std::span<bool, kHookCount> resolved,
                    std::span<bool, kHookCount> resolved,
                    std::size_t& count) noexcept {
                    std::size_t& count) noexcept {
     count = 0;
     count = 0;
+    const bool is_wine = sunrise::core::runtime::is_wine();
+
     const std::array<ExportDefinition, kHookCount> exports{
     const std::array<ExportDefinition, kHookCount> exports{
         export_definition(ModuleSlot::winsock, "connect", &winsock::connection::connect_socket),
         export_definition(ModuleSlot::winsock, "connect", &winsock::connection::connect_socket),
         export_definition(
         export_definition(
@@ -71,14 +90,27 @@ bool resolve_specs(std::span<hooking::detour::Spec, kHookCount> specs,
     for (std::size_t index = 0; index < exports.size(); ++index) {
     for (std::size_t index = 0; index < exports.size(); ++index) {
         const ExportDefinition& definition = exports[index];
         const ExportDefinition& definition = exports[index];
         const HMODULE module = module_handle(definition.module);
         const HMODULE module = module_handle(definition.module);
-        void* const target = reinterpret_cast<void*>(GetProcAddress(module, definition.name));
+        void* target = reinterpret_cast<void*>(GetProcAddress(module, definition.name));
         names[index] = definition.name;
         names[index] = definition.name;
+
+        if (target == nullptr && is_wine) {
+            const std::string_view funcName(definition.name);
+            if (funcName == "WSAConnectByList") {
+                target = reinterpret_cast<void*>(&Dummy_WSAConnectByList);
+            } else if (funcName == "GetAddrInfoExA") {
+                target = reinterpret_cast<void*>(&Dummy_GetAddrInfoExA);
+            }
+        }
+
         resolved[index] = target != nullptr;
         resolved[index] = target != nullptr;
+
         if (target == nullptr) {
         if (target == nullptr) {
-            // Older Windows builds cannot expose an egress path through an absent DnsQueryRaw.
-            return index == kRequiredHookCount;
+            if (index < kRequiredHookCount) {
+                return false;
+            }
+            continue;
         }
         }
-        specs[index] = hooking::detour::Spec{target, definition.replacement};
+        specs[count] = hooking::detour::Spec{target, definition.replacement};
         count = index + 1;
         count = index + 1;
     }
     }
     return count >= kRequiredHookCount;
     return count >= kRequiredHookCount;

+ 18 - 0
Sunrise/src/core/runtime/host_environment.cpp

@@ -0,0 +1,18 @@
+#include "host_environment.h"
+
+#include "windows.h"
+
+namespace sunrise::core::runtime {
+bool is_wine() {
+    static const bool is_linux = []() -> bool {
+        HMODULE hntdll = GetModuleHandleW(L"ntdll.dll");
+        if (!hntdll) {
+            return false;
+        }
+        return GetProcAddress(hntdll, "wine_get_version")
+               != nullptr; // Exported by wine to identify itself but not by real windows
+    }();
+
+    return is_linux;
+}
+} // namespace sunrise::core::runtime

+ 5 - 0
Sunrise/src/core/runtime/host_environment.h

@@ -0,0 +1,5 @@
+#pragma once
+
+namespace sunrise::core::runtime {
+bool is_wine();
+}

+ 5 - 0
Sunrise/src/steam/runtime/steam_lifecycle.cpp

@@ -2,10 +2,12 @@
 
 
 #include <atomic>
 #include <atomic>
 
 
+#include "../../client/graphics/wine_compat.h"
 #include "../../client/hooks/egress/runtime.h"
 #include "../../client/hooks/egress/runtime.h"
 #include "../../client/runtime/runtime.h"
 #include "../../client/runtime/runtime.h"
 #include "../../core/logging/log.h"
 #include "../../core/logging/log.h"
 #include "../../core/runtime/core_runtime.h"
 #include "../../core/runtime/core_runtime.h"
+#include "../../core/runtime/host_environment.h"
 #include "callbacks/callback_registry.h"
 #include "callbacks/callback_registry.h"
 #include "context/steam_context_state.h"
 #include "context/steam_context_state.h"
 #include "internal.h"
 #include "internal.h"
@@ -46,6 +48,9 @@ bool g_platformActivationAttempted{};
 
 
 /** Starts the Steam shim and its exported state. */
 /** Starts the Steam shim and its exported state. */
 bool initialize(void* module) noexcept {
 bool initialize(void* module) noexcept {
+    if (core::runtime::is_wine()) {
+        client::graphics::initialize_wine_display();
+    }
     if (!client::hooks::egress::install()) {
     if (!client::hooks::egress::install()) {
         return false;
         return false;
     }
     }