Merge remote-tracking branch 'upstream/develop' into 5008-beta1
						commit
						f477b82ea9
					
				@ -0,0 +1,4 @@
 | 
			
		||||
IF EXIST DF_PATH.txt SET /P _DF_PATH=<DF_PATH.txt
 | 
			
		||||
IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF
 | 
			
		||||
echo generating a build folder
 | 
			
		||||
cmake ..\.. -G"Visual Studio 17 2022" -A x64 -B VC2022 -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=1 -DBUILD_DEV_PLUGINS=1 -DBUILD_STONESENSE=1 -DBUILD_DFLAUNCH=1
 | 
			
		||||
@ -1 +1 @@
 | 
			
		||||
Subproject commit 6ed8aa46462ea01a1122fc49422840a2facc9757
 | 
			
		||||
Subproject commit d5e17c6012e7eefb0cbe3e130a56c24bd11f0094
 | 
			
		||||
@ -1 +1 @@
 | 
			
		||||
Subproject commit 439fdbc259c13f23a3122e68ba35ad5a13bcd97c
 | 
			
		||||
Subproject commit 0a994526622c2201756e386ef98b44b193e25f06
 | 
			
		||||
@ -1,7 +1,29 @@
 | 
			
		||||
project(package_windows)
 | 
			
		||||
 | 
			
		||||
if(WIN32)
 | 
			
		||||
    add_executable(launchdf WIN32 launchdf.c)
 | 
			
		||||
    install(TARGETS launchdf
 | 
			
		||||
        DESTINATION ${DFHACK_DATA_DESTINATION})
 | 
			
		||||
    if (BUILD_DFLAUNCH)
 | 
			
		||||
        if ((DEFINED ENV{steam_username}) AND (DEFINED ENV{steam_password}))
 | 
			
		||||
            # download Steam SDK
 | 
			
		||||
            set (STEAMAPI_DIR ${dfhack_SOURCE_DIR}/depends/steam)
 | 
			
		||||
            file(DOWNLOAD "https://partner.steamgames.com/downloads/steamworks_sdk_156.zip"
 | 
			
		||||
                    ${STEAMAPI_DIR}/steamworks_sdk_156.zip
 | 
			
		||||
                    EXPECTED_HASH MD5=af5a579990dbe5ae4c1b0689260d001b
 | 
			
		||||
                    USERPWD $ENV{steam_username}:$ENV{steam_password}
 | 
			
		||||
            )
 | 
			
		||||
            file(ARCHIVE_EXTRACT
 | 
			
		||||
                    INPUT ${STEAMAPI_DIR}/steamworks_sdk_156.zip
 | 
			
		||||
                    DESTINATION ${STEAMAPI_DIR})
 | 
			
		||||
            set(STEAMAPI_LIBRARY "${STEAMAPI_DIR}/sdk/redistributable_bin/win64/steam_api64.lib")
 | 
			
		||||
            set(STEAMAPI_SOURCE_DIR "${STEAMAPI_DIR}/sdk/public/steam")
 | 
			
		||||
            set(STEAMAPI_SHARED_LIBRARY "${STEAMAPI_DIR}/sdk/redistributable_bin/win64/steam_api64.dll")
 | 
			
		||||
        else()
 | 
			
		||||
            message(SEND_ERROR "Need to set steam_username and steam_password in environment to download Steamworks SDK")
 | 
			
		||||
        endif()
 | 
			
		||||
 | 
			
		||||
        include_directories(${STEAMAPI_SOURCE_DIR})
 | 
			
		||||
        link_libraries(${STEAMAPI_LIBRARY})
 | 
			
		||||
        add_executable(launchdf WIN32 launchdf.cpp)
 | 
			
		||||
        install(TARGETS launchdf DESTINATION ${DFHACK_DATA_DESTINATION})
 | 
			
		||||
        install(FILES ${STEAMAPI_SHARED_LIBRARY} DESTINATION ${DFHACK_DATA_DESTINATION})
 | 
			
		||||
    endif()
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
@ -1,72 +0,0 @@
 | 
			
		||||
#include <process.h>
 | 
			
		||||
#include <windows.h>
 | 
			
		||||
 | 
			
		||||
static BOOL is_running_on_wine() {
 | 
			
		||||
    static const char *(CDECL *pwine_get_version)(void);
 | 
			
		||||
    HMODULE hntdll = GetModuleHandle("ntdll.dll");
 | 
			
		||||
    if(!hntdll)
 | 
			
		||||
        return FALSE;
 | 
			
		||||
 | 
			
		||||
    pwine_get_version = (void *)GetProcAddress(hntdll, "wine_get_version");
 | 
			
		||||
    return !!pwine_get_version;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static LPCWSTR launch_via_steam_posix() {
 | 
			
		||||
    const char* argv[] = { "/bin/sh", "-c", "\"steam -applaunch 975370\"", NULL };
 | 
			
		||||
 | 
			
		||||
    // does not return on success
 | 
			
		||||
    _execv(argv[0], argv);
 | 
			
		||||
 | 
			
		||||
    return L"Could not launch Dwarf Fortress";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static LPCWSTR launch_via_steam_windows() {
 | 
			
		||||
    STARTUPINFOW si;
 | 
			
		||||
    PROCESS_INFORMATION pi;
 | 
			
		||||
 | 
			
		||||
    ZeroMemory(&si, sizeof(si));
 | 
			
		||||
    si.cb = sizeof(si);
 | 
			
		||||
    ZeroMemory(&pi, sizeof(pi));
 | 
			
		||||
 | 
			
		||||
    WCHAR steamPath[1024];
 | 
			
		||||
    DWORD datasize = 1024;
 | 
			
		||||
 | 
			
		||||
    LONG retCode = RegGetValueW(HKEY_CURRENT_USER, L"SOFTWARE\\Valve\\Steam",
 | 
			
		||||
            L"SteamExe", RRF_RT_REG_SZ, NULL, &steamPath, &datasize);
 | 
			
		||||
 | 
			
		||||
    if (retCode != ERROR_SUCCESS)
 | 
			
		||||
        return L"Could not find Steam client executable";
 | 
			
		||||
 | 
			
		||||
    WCHAR commandLine[1024] = L"steam.exe -applaunch 975370";
 | 
			
		||||
 | 
			
		||||
    if (CreateProcessW(steamPath, commandLine,
 | 
			
		||||
            NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi) == 0)
 | 
			
		||||
        return L"Could not launch Dwarf Fortress";
 | 
			
		||||
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// this method doesn't properly attribute Steam playtime metrics to DF,
 | 
			
		||||
// but that's better than not having DF start at all.
 | 
			
		||||
static BOOL launch_direct() {
 | 
			
		||||
    STARTUPINFOW si;
 | 
			
		||||
    PROCESS_INFORMATION pi;
 | 
			
		||||
 | 
			
		||||
    ZeroMemory(&si, sizeof(si));
 | 
			
		||||
    si.cb = sizeof(si);
 | 
			
		||||
    ZeroMemory(&pi, sizeof(pi));
 | 
			
		||||
 | 
			
		||||
    return CreateProcessW(L"Dwarf Fortress.exe",
 | 
			
		||||
            NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int WINAPI wWinMain(HINSTANCE hi, HINSTANCE hpi, PWSTR cmd, int ns) {
 | 
			
		||||
    LPCWSTR err =  is_running_on_wine() ? launch_via_steam_posix() : launch_via_steam_windows();
 | 
			
		||||
 | 
			
		||||
    if (err && !launch_direct()) {
 | 
			
		||||
        MessageBoxW(NULL, err, NULL, 0);
 | 
			
		||||
        exit(1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    exit(0);
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,223 @@
 | 
			
		||||
#include <process.h>
 | 
			
		||||
#include <windows.h>
 | 
			
		||||
#include <TlHelp32.h>
 | 
			
		||||
#include "steam_api.h"
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
const uint32 DFHACK_STEAM_APPID = 2346660;
 | 
			
		||||
const uint32 DF_STEAM_APPID = 975370;
 | 
			
		||||
 | 
			
		||||
static BOOL is_running_on_wine() {
 | 
			
		||||
    typedef const char* (CDECL wine_get_version)(void);
 | 
			
		||||
    static wine_get_version* pwine_get_version;
 | 
			
		||||
    HMODULE hntdll = GetModuleHandle("ntdll.dll");
 | 
			
		||||
    if(!hntdll)
 | 
			
		||||
        return FALSE;
 | 
			
		||||
 | 
			
		||||
    pwine_get_version = (wine_get_version*) GetProcAddress(hntdll, "wine_get_version");
 | 
			
		||||
    return !!pwine_get_version;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static LPCWSTR launch_via_steam_posix() {
 | 
			
		||||
    const char* argv[] = { "/bin/sh", "-c", "\"steam -applaunch 975370\"", NULL };
 | 
			
		||||
 | 
			
		||||
    // does not return on success
 | 
			
		||||
    _execv(argv[0], argv);
 | 
			
		||||
 | 
			
		||||
    return L"Could not launch Dwarf Fortress";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static LPCWSTR launch_via_steam_windows() {
 | 
			
		||||
    STARTUPINFOW si;
 | 
			
		||||
    PROCESS_INFORMATION pi;
 | 
			
		||||
 | 
			
		||||
    ZeroMemory(&si, sizeof(si));
 | 
			
		||||
    si.cb = sizeof(si);
 | 
			
		||||
    ZeroMemory(&pi, sizeof(pi));
 | 
			
		||||
 | 
			
		||||
    WCHAR steamPath[1024] = L"";
 | 
			
		||||
    DWORD datasize = 1024;
 | 
			
		||||
 | 
			
		||||
    LONG retCode = RegGetValueW(HKEY_CURRENT_USER, L"SOFTWARE\\Valve\\Steam",
 | 
			
		||||
            L"SteamExe", RRF_RT_REG_SZ, NULL, &steamPath, &datasize);
 | 
			
		||||
 | 
			
		||||
    if (retCode != ERROR_SUCCESS)
 | 
			
		||||
        return L"Could not find Steam client executable";
 | 
			
		||||
 | 
			
		||||
    WCHAR commandLine[1024] = L"steam.exe -applaunch 975370";
 | 
			
		||||
 | 
			
		||||
    BOOL res = CreateProcessW(steamPath, commandLine,
 | 
			
		||||
        NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
 | 
			
		||||
 | 
			
		||||
    if (res)
 | 
			
		||||
    {
 | 
			
		||||
        WaitForSingleObject(pi.hProcess, INFINITE);
 | 
			
		||||
 | 
			
		||||
        CloseHandle(pi.hProcess);
 | 
			
		||||
        CloseHandle(pi.hThread);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        return L"Could not launch Dwarf Fortress";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static LPCWSTR launch_direct() {
 | 
			
		||||
    STARTUPINFOW si;
 | 
			
		||||
    PROCESS_INFORMATION pi;
 | 
			
		||||
 | 
			
		||||
    ZeroMemory(&si, sizeof(si));
 | 
			
		||||
    si.cb = sizeof(si);
 | 
			
		||||
    ZeroMemory(&pi, sizeof(pi));
 | 
			
		||||
 | 
			
		||||
    BOOL res = CreateProcessW(L"Dwarf Fortress.exe",
 | 
			
		||||
            NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
 | 
			
		||||
 | 
			
		||||
    if (res)
 | 
			
		||||
    {
 | 
			
		||||
        WaitForSingleObject(pi.hProcess, INFINITE);
 | 
			
		||||
 | 
			
		||||
        CloseHandle(pi.hProcess);
 | 
			
		||||
        CloseHandle(pi.hThread);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return L"Could not launch via non-steam fallback method";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DWORD findDwarfFortressProcess()
 | 
			
		||||
{
 | 
			
		||||
    PROCESSENTRY32W entry;
 | 
			
		||||
    entry.dwSize = sizeof(PROCESSENTRY32W);
 | 
			
		||||
 | 
			
		||||
    const auto snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
 | 
			
		||||
 | 
			
		||||
    if (!Process32FirstW(snapshot, &entry))
 | 
			
		||||
    {
 | 
			
		||||
        CloseHandle(snapshot);
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    do {
 | 
			
		||||
        std::wstring executableName(entry.szExeFile);
 | 
			
		||||
        if (executableName == L"Dwarf Fortress.exe")
 | 
			
		||||
        {
 | 
			
		||||
            CloseHandle(snapshot);
 | 
			
		||||
            return entry.th32ProcessID;
 | 
			
		||||
        }
 | 
			
		||||
    } while (Process32NextW(snapshot, &entry));
 | 
			
		||||
 | 
			
		||||
    CloseHandle(snapshot);
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nShowCmd) {
 | 
			
		||||
 | 
			
		||||
    // initialize steam context
 | 
			
		||||
    if (SteamAPI_RestartAppIfNecessary(DFHACK_STEAM_APPID))
 | 
			
		||||
    {
 | 
			
		||||
        exit(0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!SteamAPI_Init())
 | 
			
		||||
    {
 | 
			
		||||
        // could not initialize steam context, attempt fallback launch
 | 
			
		||||
        LPCWSTR err = launch_direct();
 | 
			
		||||
        if (err != NULL)
 | 
			
		||||
        {
 | 
			
		||||
            MessageBoxW(NULL, err, NULL, 0);
 | 
			
		||||
            exit(1);
 | 
			
		||||
        }
 | 
			
		||||
        exit(0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool wine = is_running_on_wine();
 | 
			
		||||
 | 
			
		||||
    if (wine)
 | 
			
		||||
    {
 | 
			
		||||
        // attempt launch via steam client
 | 
			
		||||
        LPCWSTR err = launch_via_steam_posix();
 | 
			
		||||
 | 
			
		||||
        if (err != NULL)
 | 
			
		||||
            // steam client launch failed, attempt fallback launch
 | 
			
		||||
            err = launch_direct();
 | 
			
		||||
 | 
			
		||||
        if (err != NULL)
 | 
			
		||||
        {
 | 
			
		||||
            MessageBoxW(NULL, err, NULL, 0);
 | 
			
		||||
            exit(1);
 | 
			
		||||
        }
 | 
			
		||||
        exit(0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // steam detected and not running in wine
 | 
			
		||||
 | 
			
		||||
    bool df_installed = SteamApps()->BIsAppInstalled(DF_STEAM_APPID);
 | 
			
		||||
 | 
			
		||||
    if (!df_installed)
 | 
			
		||||
    {
 | 
			
		||||
        // Steam DF is not installed. Assume DF is installed in same directory as DFHack and do a fallback launch
 | 
			
		||||
        LPCWSTR err = launch_direct();
 | 
			
		||||
 | 
			
		||||
        if (err != NULL)
 | 
			
		||||
        {
 | 
			
		||||
            MessageBoxW(NULL, err, NULL, 0);
 | 
			
		||||
            exit(1);
 | 
			
		||||
        }
 | 
			
		||||
        exit(0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // obtain DF app path
 | 
			
		||||
 | 
			
		||||
    char buf[2048] = "";
 | 
			
		||||
 | 
			
		||||
    int b1 = SteamApps()->GetAppInstallDir(DFHACK_STEAM_APPID, (char*)&buf, 2048);
 | 
			
		||||
    std::string dfhack_install_folder = (b1 != -1) ? std::string(buf) : "";
 | 
			
		||||
 | 
			
		||||
    int b2 = SteamApps()->GetAppInstallDir(DF_STEAM_APPID, (char*)&buf, 2048);
 | 
			
		||||
    std::string df_install_folder = (b2 != -1) ? std::string(buf) : "";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    if (df_install_folder != dfhack_install_folder)
 | 
			
		||||
    {
 | 
			
		||||
        // DF and DFHack are not installed in the same library
 | 
			
		||||
        MessageBoxW(NULL, L"DFHack and Dwarf Fortress must be installed in the same Steam library.\nAborting.", NULL, 0);
 | 
			
		||||
        exit(1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    DWORD df_pid = findDwarfFortressProcess();
 | 
			
		||||
 | 
			
		||||
    if (df_pid == -1)
 | 
			
		||||
    {
 | 
			
		||||
        LPCWSTR err = launch_via_steam_windows();
 | 
			
		||||
        if (err != NULL)
 | 
			
		||||
        {
 | 
			
		||||
            MessageBoxW(NULL, err, NULL, 0);
 | 
			
		||||
            exit(1);
 | 
			
		||||
        }
 | 
			
		||||
        int counter = 0;
 | 
			
		||||
 | 
			
		||||
        do {
 | 
			
		||||
            if (counter++ > 60)
 | 
			
		||||
            {
 | 
			
		||||
                MessageBoxW(NULL, L"Dwarf Fortress took too long to launch, aborting", NULL, 0);
 | 
			
		||||
                exit(1);
 | 
			
		||||
            }
 | 
			
		||||
            Sleep(1000);
 | 
			
		||||
            df_pid = findDwarfFortressProcess();
 | 
			
		||||
        } while (df_pid == -1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    HANDLE hDF = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, df_pid);
 | 
			
		||||
 | 
			
		||||
    // in the future open an IPC connection so that we can proxy SteamAPI calls for the DFSteam module
 | 
			
		||||
 | 
			
		||||
    // this will eventuallyh need to become a loop with a WaitForMultipleObjects call
 | 
			
		||||
    WaitForSingleObject(hDF, INFINITE);
 | 
			
		||||
 | 
			
		||||
    CloseHandle(hDF);
 | 
			
		||||
 | 
			
		||||
    exit(0);
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,3 @@
 | 
			
		||||
*.pb.cc
 | 
			
		||||
*.pb.cc.rule
 | 
			
		||||
*.pb.h
 | 
			
		||||
@ -1 +1 @@
 | 
			
		||||
Subproject commit ec1a69788fd6329008672523b622fd8b390fea73
 | 
			
		||||
Subproject commit 6fba9905a71f626ecc640fd3de988e147d16cb4e
 | 
			
		||||
		Loading…
	
		Reference in New Issue