From 9cee5004d774dff2091bc9e2db331d60e8185ba5 Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Sun, 20 Mar 2022 16:00:30 -0400
Subject: [PATCH 01/67] Fix ISteamClient class member ordering for
Steam_Unified_Messages.
Some games, like SAO:FB, require a specific class member order.
---
dll/steam_client.cpp | 2 +-
dll/steam_client.h | 3 ++-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/dll/steam_client.cpp b/dll/steam_client.cpp
index 17af33e..101d089 100644
--- a/dll/steam_client.cpp
+++ b/dll/steam_client.cpp
@@ -81,6 +81,7 @@ Steam_Client::Steam_Client()
steam_remote_storage = new Steam_Remote_Storage(settings_client, local_storage, callback_results_client);
steam_screenshots = new Steam_Screenshots(local_storage, callbacks_client);
steam_http = new Steam_HTTP(settings_client, network, callback_results_client, callbacks_client);
+ steam_unified_messages = new Steam_Unified_Messages(settings_client, network, callback_results_client, callbacks_client, run_every_runcb);
steam_controller = new Steam_Controller(settings_client, callback_results_client, callbacks_client, run_every_runcb);
steam_ugc = new Steam_UGC(settings_client, callback_results_client, callbacks_client);
steam_applist = new Steam_Applist();
@@ -95,7 +96,6 @@ Steam_Client::Steam_Client()
steam_networking_messages = new Steam_Networking_Messages(settings_client, network, callback_results_client, callbacks_client, run_every_runcb);
steam_game_coordinator = new Steam_Game_Coordinator(settings_client, network, callback_results_client, callbacks_client, run_every_runcb);
steam_networking_utils = new Steam_Networking_Utils(settings_client, network, callback_results_client, callbacks_client, run_every_runcb);
- steam_unified_messages = new Steam_Unified_Messages(settings_client, network, callback_results_client, callbacks_client, run_every_runcb);
steam_game_search = new Steam_Game_Search(settings_client, network, callback_results_client, callbacks_client, run_every_runcb);
steam_parties = new Steam_Parties(settings_client, network, callback_results_client, callbacks_client, run_every_runcb);
steam_remoteplay = new Steam_RemotePlay(settings_client, network, callback_results_client, callbacks_client, run_every_runcb);
diff --git a/dll/steam_client.h b/dll/steam_client.h
index d00cb6a..37c4a85 100644
--- a/dll/steam_client.h
+++ b/dll/steam_client.h
@@ -75,6 +75,7 @@ public ISteamClient018,
public ISteamClient019,
public ISteamClient
{
+// Some games (SAO:FB) use pointer math to access the class so member order is important.
public:
Networking *network;
SteamCallResults *callback_results_server, *callback_results_client;
@@ -94,6 +95,7 @@ public:
Steam_Remote_Storage *steam_remote_storage;
Steam_Screenshots *steam_screenshots;
Steam_HTTP *steam_http;
+ Steam_Unified_Messages *steam_unified_messages;
Steam_Controller *steam_controller;
Steam_UGC *steam_ugc;
Steam_Applist *steam_applist;
@@ -108,7 +110,6 @@ public:
Steam_Networking_Messages *steam_networking_messages;
Steam_Game_Coordinator *steam_game_coordinator;
Steam_Networking_Utils *steam_networking_utils;
- Steam_Unified_Messages *steam_unified_messages;
Steam_Game_Search *steam_game_search;
Steam_Parties *steam_parties;
Steam_RemotePlay *steam_remoteplay;
From d29103bf79538d9116f757c634058ad1e6ae7e37 Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Thu, 24 Mar 2022 02:57:55 -0400
Subject: [PATCH 02/67] Create shared mem mapping in steamclient_loader.
The mapping and it's event object are needed by some games.
---
steamclient_loader/ColdClientLoader.cpp | 38 +++++++++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/steamclient_loader/ColdClientLoader.cpp b/steamclient_loader/ColdClientLoader.cpp
index 6e790ab..ed59f24 100644
--- a/steamclient_loader/ColdClientLoader.cpp
+++ b/steamclient_loader/ColdClientLoader.cpp
@@ -32,6 +32,9 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
WCHAR ExeRunDir[MAX_PATH] = { 0 };
WCHAR ExeCommandLine[4096] = { 0 };
WCHAR AppId[128] = { 0 };
+ HANDLE SharedMemFileMap = 0;
+ HANDLE SharedMemFileView = 0;
+ HANDLE SharedMemFileLock = 0;
STARTUPINFOW info = { sizeof(info) };
PROCESS_INFORMATION processInfo;
@@ -100,11 +103,38 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
return 0;
}
+ // Create shared mem map.
+ SharedMemFileMap = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 1024, L"Local\\SteamStart_SharedMemFile");
+ if (!SharedMemFileMap)
+ {
+ MessageBoxA(NULL, "Unable to create shared memory mapping.", "ColdClientLoader", MB_ICONERROR);
+ return 0;
+ }
+ SharedMemFileView = MapViewOfFile(SharedMemFileMap, SECTION_ALL_ACCESS, 0, 0, 0);
+ if (!SharedMemFileView)
+ {
+ MessageBoxA(NULL, "Unable to create view of shared memory mapping.", "ColdClientLoader", MB_ICONERROR);
+ CloseHandle(SharedMemFileMap);
+ return 0;
+ }
+ SharedMemFileLock = CreateEventW(NULL, FALSE, FALSE, L"Local\\SteamStart_SharedMemLock");
+ if (!SharedMemFileLock)
+ {
+ MessageBoxA(NULL, "Unable to create lock for shared memory mapping.", "ColdClientLoader", MB_ICONERROR);
+ CloseHandle(SharedMemFileView);
+ CloseHandle(SharedMemFileMap);
+ return 0;
+ }
+ SetEvent(SharedMemFileLock);
+
WCHAR CommandLine[8192];
_snwprintf(CommandLine, _countof(CommandLine), L"\"%ls\" %ls", ExeFile, ExeCommandLine);
if (!ExeFile[0] || !CreateProcessW(ExeFile, CommandLine, NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, ExeRunDir, &info, &processInfo))
{
MessageBoxA(NULL, "Unable to load the requested EXE file.", "ColdClientLoader", MB_ICONERROR);
+ CloseHandle(SharedMemFileLock);
+ CloseHandle(SharedMemFileView);
+ CloseHandle(SharedMemFileMap);
return 0;
}
HKEY Registrykey;
@@ -130,6 +160,9 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
{
MessageBoxA(NULL, "Unable to patch Steam process informations on the Windows registry.", "ColdClientLoader", MB_ICONERROR);
TerminateProcess(processInfo.hProcess, NULL);
+ CloseHandle(SharedMemFileLock);
+ CloseHandle(SharedMemFileView);
+ CloseHandle(SharedMemFileMap);
return 0;
}
}
@@ -175,5 +208,10 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
}
}
+ // Close the SharedMem handles.
+ CloseHandle(SharedMemFileLock);
+ CloseHandle(SharedMemFileView);
+ CloseHandle(SharedMemFileMap);
+
return 0;
}
From 0d0ec28ecb5dd89054b7b51d0ba96c3dba9259f0 Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Tue, 29 Mar 2022 12:27:14 -0400
Subject: [PATCH 03/67] Make a better stub for Steam_RemotePlay functionality.
Note for googler's, this doesn't mean RemotePlay works / is being implemented.
Put the main stuff into its own .cpp.
Set up storage for holding descriptions. (*NOT* thread safe!)
Clears up a crash on init in SAO:FB.
---
dll/steam_remoteplay.cpp | 202 +++++++++++++++++++++++++++++++++++++++
dll/steam_remoteplay.h | 36 ++-----
2 files changed, 208 insertions(+), 30 deletions(-)
create mode 100644 dll/steam_remoteplay.cpp
diff --git a/dll/steam_remoteplay.cpp b/dll/steam_remoteplay.cpp
new file mode 100644
index 0000000..c182b76
--- /dev/null
+++ b/dll/steam_remoteplay.cpp
@@ -0,0 +1,202 @@
+/* Copyright (C) 2019 Mr Goldberg
+ This file is part of the Goldberg Emulator
+
+ The Goldberg Emulator is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ The Goldberg Emulator is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the Goldberg Emulator; if not, see
+ . */
+
+#include "steam_remoteplay.h"
+#include
+#include
+
+typedef struct remote_play_session_info_T {
+ RemotePlaySessionID_t session_id;
+ CSteamID connected_user;
+ const char * client_name;
+ ESteamDeviceFormFactor client_form_factor;
+ int client_resolution_x;
+ int client_resolution_y;
+} remote_play_session_info;
+//TODO: NOT thread safe!!!
+static std::vector remote_play_sessions;
+
+int create_remote_play_session_info( RemotePlaySessionID_t session_id, CSteamID connected_user, const char * client_name, ESteamDeviceFormFactor client_form_factor, int client_resolution_x, int client_resolution_y ) {
+ remote_play_session_info session_info;
+ size_t buffer_length = 0;
+ char * buffer = NULL;
+
+ if ((remote_play_sessions.size() < UINT_MAX) && (client_name != NULL)) {
+ session_info.session_id = session_id;
+ session_info.connected_user = connected_user;
+ session_info.client_form_factor = client_form_factor;
+ session_info.client_resolution_x = client_resolution_x;
+ session_info.client_resolution_y = client_resolution_y;
+
+ buffer_length = strlen( client_name );
+ if (buffer_length > 0) {
+ buffer = new char[buffer_length + 1];
+ if (buffer != NULL) {
+ memcpy(buffer, client_name, buffer_length);
+ session_info.client_name = buffer;
+ remote_play_sessions.push_back( (const remote_play_session_info)session_info );
+ return 0;
+ }
+ }
+ }
+ return -1;
+}
+
+int destroy_remote_play_session_info( size_t index ) {
+ if (remote_play_sessions.size() < index) {
+ delete remote_play_sessions[index].client_name;
+ remote_play_sessions.erase(remote_play_sessions.begin() + index);
+ return 0;
+ }
+ return -1;
+}
+
+uint32 get_number_of_remote_play_sessions() {
+ return (uint32)remote_play_sessions.size();
+}
+
+int get_remote_play_session_id( size_t index, RemotePlaySessionID_t * session_id ) {
+ if ((session_id != NULL) && (index >= 0) && (remote_play_sessions.size() < index)) {
+ *session_id = remote_play_sessions[index].session_id;
+ return 0;
+ }
+ return -1;
+}
+
+int get_remote_play_session_index( RemotePlaySessionID_t session_id, size_t * index ) {
+ size_t count = 0;
+
+ if ((index != NULL) && (remote_play_sessions.size() > 0)) {
+ for (std::vector::iterator iter = remote_play_sessions.begin(); iter != remote_play_sessions.end(); iter++) {
+ if (iter->session_id == session_id) {
+ *index = count;
+ return 0;
+ }
+ count++;
+ }
+ }
+ return -1;
+}
+
+int get_remote_play_session_connected_user( size_t index, CSteamID * connected_user ) {
+ if ((connected_user != NULL) && (index >= 0) && (remote_play_sessions.size() < index)) {
+ *connected_user = remote_play_sessions[index].connected_user;
+ return 0;
+ }
+ return -1;
+}
+
+int get_remote_play_session_client_name( size_t index, const char ** client_name ) {
+ if ((client_name != NULL) && (index >= 0) && (remote_play_sessions.size() < index)) {
+ *client_name = remote_play_sessions[index].client_name;
+ return 0;
+ }
+ return -1;
+}
+
+int get_remote_play_session_client_form_factor( size_t index, ESteamDeviceFormFactor * client_form_factor ) {
+ if ((client_form_factor != NULL) && (index >= 0) && (remote_play_sessions.size() < index)) {
+ *client_form_factor = remote_play_sessions[index].client_form_factor;
+ return 0;
+ }
+ return -1;
+}
+
+int get_remote_play_session_client_resolutions( size_t index, int * client_resolution_x, int * client_resolution_y ) {
+ if ((client_resolution_x != NULL) && (client_resolution_y != NULL) && (index >= 0) && (remote_play_sessions.size() < index)) {
+ *client_resolution_x = remote_play_sessions[index].client_resolution_x;
+ *client_resolution_y = remote_play_sessions[index].client_resolution_y;
+ return 0;
+ }
+ return -1;
+}
+
+uint32 Steam_RemotePlay::GetSessionCount()
+{
+ PRINT_DEBUG("Steam_RemotePlay::GetSessionCount\n");
+ return get_number_of_remote_play_sessions();
+}
+
+uint32 Steam_RemotePlay::GetSessionID( int iSessionIndex )
+{
+ RemotePlaySessionID_t session_id;
+
+ PRINT_DEBUG("Steam_RemotePlay::GetSessionID\n");
+ return ((get_remote_play_session_id( iSessionIndex, &session_id ) == 0) ? (session_id) : (0));
+}
+
+CSteamID Steam_RemotePlay::GetSessionSteamID( uint32 unSessionID )
+{
+ CSteamID steam_id = k_steamIDNil;
+ size_t index = 0;
+
+ PRINT_DEBUG("Steam_RemotePlay::GetSessionSteamID\n");
+ if (get_remote_play_session_index( unSessionID, &index ) == 0) {
+ if (get_remote_play_session_connected_user( index, &steam_id ) == 0) {
+ return steam_id;
+ }
+ }
+ return k_steamIDNil;
+}
+
+const char * Steam_RemotePlay::GetSessionClientName( uint32 unSessionID )
+{
+ const char * client_name = NULL;
+ size_t index = 0;
+
+ PRINT_DEBUG("Steam_RemotePlay::GetSessionClientName\n");
+ if (get_remote_play_session_index( unSessionID, &index ) == 0) {
+ if (get_remote_play_session_client_name( index, &client_name ) == 0) {
+ return client_name;
+ }
+ }
+ return NULL;
+}
+
+ESteamDeviceFormFactor Steam_RemotePlay::GetSessionClientFormFactor( uint32 unSessionID )
+{
+ ESteamDeviceFormFactor form_factor = k_ESteamDeviceFormFactorUnknown;
+ size_t index = 0;
+
+ PRINT_DEBUG("Steam_RemotePlay::GetSessionClientFormFactor\n");
+ if (get_remote_play_session_index( unSessionID, &index ) == 0) {
+ if (get_remote_play_session_client_form_factor( index, &form_factor ) == 0) {
+ return form_factor;
+ }
+ }
+ return k_ESteamDeviceFormFactorUnknown;
+}
+
+bool Steam_RemotePlay::BGetSessionClientResolution( uint32 unSessionID, int *pnResolutionX, int *pnResolutionY )
+{
+ int x = 0;
+ int y = 0;
+ size_t index = 0;
+
+ PRINT_DEBUG("Steam_RemotePlay::BGetSessionClientResolution\n");
+ if ((pnResolutionX != NULL) && (pnResolutionY != NULL)) {
+ if (get_remote_play_session_index( unSessionID, &index ) == 0) {
+ if (get_remote_play_session_client_resolutions( index, &x, &y ) == 0) {
+ *pnResolutionX = x;
+ *pnResolutionY = y;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
diff --git a/dll/steam_remoteplay.h b/dll/steam_remoteplay.h
index 7bd97ff..56e2965 100644
--- a/dll/steam_remoteplay.h
+++ b/dll/steam_remoteplay.h
@@ -62,48 +62,24 @@ Steam_RemotePlay(class Settings *settings, class Networking *network, class Stea
}
// Get the number of currently connected Steam Remote Play sessions
-uint32 GetSessionCount()
-{
- PRINT_DEBUG("Steam_RemotePlay::GetSessionCount\n");
- return 0;
-}
+uint32 GetSessionCount();
// Get the currently connected Steam Remote Play session ID at the specified index. Returns zero if index is out of bounds.
-uint32 GetSessionID( int iSessionIndex )
-{
- PRINT_DEBUG("Steam_RemotePlay::GetSessionID\n");
- return 0;
-}
+uint32 GetSessionID( int iSessionIndex );
// Get the SteamID of the connected user
-CSteamID GetSessionSteamID( uint32 unSessionID )
-{
- PRINT_DEBUG("Steam_RemotePlay::GetSessionSteamID\n");
- return k_steamIDNil;
-}
+CSteamID GetSessionSteamID( uint32 unSessionID );
// Get the name of the session client device
// This returns NULL if the sessionID is not valid
-const char *GetSessionClientName( uint32 unSessionID )
-{
- PRINT_DEBUG("Steam_RemotePlay::GetSessionClientName\n");
- return NULL;
-}
+const char *GetSessionClientName( uint32 unSessionID );
// Get the form factor of the session client device
-ESteamDeviceFormFactor GetSessionClientFormFactor( uint32 unSessionID )
-{
- PRINT_DEBUG("Steam_RemotePlay::GetSessionClientFormFactor\n");
- return k_ESteamDeviceFormFactorUnknown;
-}
+ESteamDeviceFormFactor GetSessionClientFormFactor( uint32 unSessionID );
// Get the resolution, in pixels, of the session client device
// This is set to 0x0 if the resolution is not available
-bool BGetSessionClientResolution( uint32 unSessionID, int *pnResolutionX, int *pnResolutionY )
-{
- PRINT_DEBUG("Steam_RemotePlay::BGetSessionClientResolution\n");
- return false;
-}
+bool BGetSessionClientResolution( uint32 unSessionID, int *pnResolutionX, int *pnResolutionY );
// Invite a friend to Remote Play Together
// This returns false if the invite can't be sent
From 40429741002978199fdc3155abf8549377339f9b Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Wed, 10 Jan 2024 04:17:51 -0500
Subject: [PATCH 04/67] Add gitattributes file so shell scripts don't get
mangled and break builds.
Signed-off-by: redpolline <11156324-redpolline@users.noreply.gitlab.com>
---
.gitattributes | 13 +++++++++++++
1 file changed, 13 insertions(+)
create mode 100644 .gitattributes
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..9021357
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,13 @@
+# Set the default behavior.
+* text=auto
+
+# Unix shell files should always be LF.
+*.sh text eol=lf
+
+# Windows shell files should always be CRLF.
+*.bat text eol=crlf
+
+# Binary files.
+*.jpg binary
+*.png binary
+
From b0796076349b25dbfa14d7605f59835c53b124ce Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Wed, 10 Jan 2024 04:19:06 -0500
Subject: [PATCH 05/67] Fix linux build script, and add lobby_connect to it.
Signed-off-by: redpolline <11156324-redpolline@users.noreply.gitlab.com>
---
build_linux.sh | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/build_linux.sh b/build_linux.sh
index 1d29569..74c0a49 100755
--- a/build_linux.sh
+++ b/build_linux.sh
@@ -1,2 +1,4 @@
-protoc -I./dll/ --cpp_out=./dll/ ./dll/*.proto
-clang++ -shared -fPIC -o libsteam_api.so dll/*.cpp dll/*.cc -g3 -Wno-return-type -fsanitize=address -lasan -lprotobuf-lite -std=c++14 && echo built
+#!/bin/bash
+protoc -I"${PWD}/dll/" --cpp_out="${PWD}/dll/" "${PWD}"/dll/*.proto
+clang++ -shared -fPIC -o libsteam_api.so dll/*.cpp dll/*.cc -g3 -Wno-return-type -fsanitize=address -lasan -lprotobuf-lite -std=c++14 && echo built libsteam_api.so
+clang++ -fPIC -o lobby_connect lobby_connect.cpp dll/*.cpp dll/*.cc -g3 -Wno-return-type -fsanitize=address -lasan -lprotobuf-lite -std=c++14 && echo built lobby_connect
\ No newline at end of file
From 2e3f14e7bdb00ed260716b6424174a723fd0cf2a Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Wed, 10 Jan 2024 04:20:11 -0500
Subject: [PATCH 06/67] Fix copy-paste syntax error in steam_ugc.h.
Signed-off-by: redpolline <11156324-redpolline@users.noreply.gitlab.com>
---
dll/steam_ugc.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dll/steam_ugc.h b/dll/steam_ugc.h
index b1ada44..77658b2 100644
--- a/dll/steam_ugc.h
+++ b/dll/steam_ugc.h
@@ -600,13 +600,13 @@ bool RemoveItemPreview( UGCUpdateHandle_t handle, uint32 index )
bool AddContentDescriptor( UGCUpdateHandle_t handle, EUGCContentDescriptorID descid )
{
- PRINT_DEBUG("Steam_UGC::AddContentDescriptor %llu %u\n", handle, index);
+ PRINT_DEBUG("Steam_UGC::AddContentDescriptor %llu %u\n", handle, descid);
return false;
}
bool RemoveContentDescriptor( UGCUpdateHandle_t handle, EUGCContentDescriptorID descid )
{
- PRINT_DEBUG("Steam_UGC::RemoveContentDescriptor %llu %u\n", handle, index);
+ PRINT_DEBUG("Steam_UGC::RemoveContentDescriptor %llu %u\n", handle, descid);
return false;
}
From 92623f586d954a3f201d123e863f9cec8f2b5a08 Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Wed, 10 Jan 2024 04:27:41 -0500
Subject: [PATCH 07/67] Fix too many env vars causing build failures, and put
debug builds in their own folder like release builds.
Cannot call the vc vars batch too many times. Fix it by calling set/end local.
See also: https://developercommunity.visualstudio.com/t/vcvarsallbat-reports-the-input-line-is-too-long-if/257260
Signed-off-by: redpolline <11156324-redpolline@users.noreply.gitlab.com>
---
build_win_debug_experimental.bat | 16 ++++++++++++----
build_win_debug_experimental_steamclient.bat | 12 ++++++++++--
build_win_find_interfaces.bat | 2 ++
build_win_lobby_connect.bat | 2 ++
build_win_release.bat | 4 ++++
build_win_release_experimental.bat | 4 ++++
build_win_release_experimental_steamclient.bat | 4 ++++
7 files changed, 38 insertions(+), 6 deletions(-)
diff --git a/build_win_debug_experimental.bat b/build_win_debug_experimental.bat
index 7f3a080..f92957b 100755
--- a/build_win_debug_experimental.bat
+++ b/build_win_debug_experimental.bat
@@ -1,14 +1,22 @@
@echo off
cd /d "%~dp0"
call build_set_protobuf_directories.bat
+
+mkdir debug
+mkdir debug\experimental
+
+setlocal
"%PROTOC_X86_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
call build_env_x86.bat
cl dll/rtlgenrandom.c dll/rtlgenrandom.def
-cl /Z7 /LD /IImGui /I%PROTOBUF_X86_DIRECTORY%\include\ /DEMU_EXPERIMENTAL_BUILD /DCONTROLLER_SUPPORT /DEMU_OVERLAY /Ioverlay_experimental dll/*.cpp dll/*.cc detours/*.cpp controller/gamepad.c ImGui/*.cpp ImGui/backends/imgui_impl_dx*.cpp ImGui/backends/imgui_impl_win32.cpp ImGui/backends/imgui_impl_vulkan.cpp ImGui/backends/imgui_impl_opengl3.cpp ImGui/backends/imgui_win_shader_blobs.cpp overlay_experimental/*.cpp overlay_experimental/windows/*.cpp overlay_experimental/System/*.cpp "%PROTOBUF_X86_LIBRARY%" opengl32.lib Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Winmm.lib /EHsc /MP12 /link /OUT:steam_api.dll
-cl /LD steamclient.cpp /EHsc /MP12 /link /OUT:steamclient.dll
+cl /Z7 /LD /IImGui /I%PROTOBUF_X86_DIRECTORY%\include\ /DEMU_EXPERIMENTAL_BUILD /DCONTROLLER_SUPPORT /DEMU_OVERLAY /Ioverlay_experimental dll/*.cpp dll/*.cc detours/*.cpp controller/gamepad.c ImGui/*.cpp ImGui/backends/imgui_impl_dx*.cpp ImGui/backends/imgui_impl_win32.cpp ImGui/backends/imgui_impl_vulkan.cpp ImGui/backends/imgui_impl_opengl3.cpp ImGui/backends/imgui_win_shader_blobs.cpp overlay_experimental/*.cpp overlay_experimental/windows/*.cpp overlay_experimental/System/*.cpp "%PROTOBUF_X86_LIBRARY%" opengl32.lib Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Winmm.lib /EHsc /MP12 /link /OUT:debug\experimental\steam_api.dll
+cl /LD steamclient.cpp /EHsc /MP12 /link /OUT:debug\experimental\steamclient.dll
+endlocal
+setlocal
"%PROTOC_X64_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
call build_env_x64.bat
cl dll/rtlgenrandom.c dll/rtlgenrandom.def
-cl /Z7 /LD /IImGui /I%PROTOBUF_X64_DIRECTORY%\include\ /DEMU_EXPERIMENTAL_BUILD /DCONTROLLER_SUPPORT /DEMU_OVERLAY /Ioverlay_experimental dll/*.cpp dll/*.cc detours/*.cpp controller/gamepad.c ImGui/*.cpp ImGui/backends/imgui_impl_dx*.cpp ImGui/backends/imgui_impl_win32.cpp ImGui/backends/imgui_impl_vulkan.cpp ImGui/backends/imgui_impl_opengl3.cpp ImGui/backends/imgui_win_shader_blobs.cpp overlay_experimental/*.cpp overlay_experimental/windows/*.cpp overlay_experimental/System/*.cpp "%PROTOBUF_X64_LIBRARY%" opengl32.lib Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Winmm.lib /EHsc /MP12 /link /OUT:steam_api64.dll
-cl /LD steamclient.cpp /EHsc /MP12 /link /OUT:steamclient64.dll
+cl /Z7 /LD /IImGui /I%PROTOBUF_X64_DIRECTORY%\include\ /DEMU_EXPERIMENTAL_BUILD /DCONTROLLER_SUPPORT /DEMU_OVERLAY /Ioverlay_experimental dll/*.cpp dll/*.cc detours/*.cpp controller/gamepad.c ImGui/*.cpp ImGui/backends/imgui_impl_dx*.cpp ImGui/backends/imgui_impl_win32.cpp ImGui/backends/imgui_impl_vulkan.cpp ImGui/backends/imgui_impl_opengl3.cpp ImGui/backends/imgui_win_shader_blobs.cpp overlay_experimental/*.cpp overlay_experimental/windows/*.cpp overlay_experimental/System/*.cpp "%PROTOBUF_X64_LIBRARY%" opengl32.lib Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Winmm.lib /EHsc /MP12 /link /OUT:debug\experimental\steam_api64.dll
+cl /LD steamclient.cpp /EHsc /MP12 /link /OUT:debug\experimental\steamclient64.dll
+endlocal
\ No newline at end of file
diff --git a/build_win_debug_experimental_steamclient.bat b/build_win_debug_experimental_steamclient.bat
index 1eec4aa..4e7517b 100644
--- a/build_win_debug_experimental_steamclient.bat
+++ b/build_win_debug_experimental_steamclient.bat
@@ -1,9 +1,17 @@
cd /d "%~dp0"
+
+mkdir debug
+mkdir debug\experimental_steamclient
+
call build_set_protobuf_directories.bat
+setlocal
"%PROTOC_X86_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
call build_env_x86.bat
cl dll/rtlgenrandom.c dll/rtlgenrandom.def
-cl /LD /IImGui /I%PROTOBUF_X86_DIRECTORY%\include\ /DSTEAMCLIENT_DLL /DCONTROLLER_SUPPORT /DEMU_EXPERIMENTAL_BUILD /DEMU_OVERLAY /Ioverlay_experimental dll/*.cpp dll/*.cc detours/*.cpp controller/gamepad.c ImGui/*.cpp ImGui/backends/imgui_impl_dx*.cpp ImGui/backends/imgui_impl_win32.cpp ImGui/backends/imgui_impl_vulkan.cpp ImGui/backends/imgui_impl_opengl3.cpp ImGui/backends/imgui_win_shader_blobs.cpp overlay_experimental/*.cpp overlay_experimental/windows/*.cpp overlay_experimental/System/*.cpp "%PROTOBUF_X86_LIBRARY%" opengl32.lib Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Winmm.lib /EHsc /MP12 /link /OUT:steamclient.dll
+cl /LD /IImGui /I%PROTOBUF_X86_DIRECTORY%\include\ /DSTEAMCLIENT_DLL /DCONTROLLER_SUPPORT /DEMU_EXPERIMENTAL_BUILD /DEMU_OVERLAY /Ioverlay_experimental dll/*.cpp dll/*.cc detours/*.cpp controller/gamepad.c ImGui/*.cpp ImGui/backends/imgui_impl_dx*.cpp ImGui/backends/imgui_impl_win32.cpp ImGui/backends/imgui_impl_vulkan.cpp ImGui/backends/imgui_impl_opengl3.cpp ImGui/backends/imgui_win_shader_blobs.cpp overlay_experimental/*.cpp overlay_experimental/windows/*.cpp overlay_experimental/System/*.cpp "%PROTOBUF_X86_LIBRARY%" opengl32.lib Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Winmm.lib /EHsc /MP12 /link /OUT:debug\experimental_steamclient\steamclient.dll
+endlocal
+setlocal
call build_env_x64.bat
cl dll/rtlgenrandom.c dll/rtlgenrandom.def
-cl /LD /IImGui /I%PROTOBUF_X64_DIRECTORY%\include\ /DSTEAMCLIENT_DLL /DCONTROLLER_SUPPORT /DEMU_EXPERIMENTAL_BUILD /DEMU_OVERLAY /Ioverlay_experimental dll/*.cpp dll/*.cc detours/*.cpp controller/gamepad.c ImGui/*.cpp ImGui/backends/imgui_impl_dx*.cpp ImGui/backends/imgui_impl_win32.cpp ImGui/backends/imgui_impl_vulkan.cpp ImGui/backends/imgui_impl_opengl3.cpp ImGui/backends/imgui_win_shader_blobs.cpp overlay_experimental/*.cpp overlay_experimental/windows/*.cpp overlay_experimental/System/*.cpp "%PROTOBUF_X64_LIBRARY%" opengl32.lib Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Winmm.lib /EHsc /MP12 /link /OUT:steamclient64.dll
+cl /LD /IImGui /I%PROTOBUF_X64_DIRECTORY%\include\ /DSTEAMCLIENT_DLL /DCONTROLLER_SUPPORT /DEMU_EXPERIMENTAL_BUILD /DEMU_OVERLAY /Ioverlay_experimental dll/*.cpp dll/*.cc detours/*.cpp controller/gamepad.c ImGui/*.cpp ImGui/backends/imgui_impl_dx*.cpp ImGui/backends/imgui_impl_win32.cpp ImGui/backends/imgui_impl_vulkan.cpp ImGui/backends/imgui_impl_opengl3.cpp ImGui/backends/imgui_win_shader_blobs.cpp overlay_experimental/*.cpp overlay_experimental/windows/*.cpp overlay_experimental/System/*.cpp "%PROTOBUF_X64_LIBRARY%" opengl32.lib Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Winmm.lib /EHsc /MP12 /link /OUT:debug\experimental_steamclient\steamclient64.dll
+endlocal
diff --git a/build_win_find_interfaces.bat b/build_win_find_interfaces.bat
index cb1cb48..db3b46a 100755
--- a/build_win_find_interfaces.bat
+++ b/build_win_find_interfaces.bat
@@ -2,8 +2,10 @@
cd /d "%~dp0"
mkdir release\tools
del /Q release\tools\*
+setlocal
call build_env_x86.bat
cl generate_interfaces_file.cpp /EHsc /MP12 /Ox /link /debug:none /OUT:release\tools\generate_interfaces_file.exe
del /Q /S release\tools\*.lib
del /Q /S release\tools\*.exp
copy Readme_generate_interfaces.txt release\tools\Readme_generate_interfaces.txt
+endlocal
diff --git a/build_win_lobby_connect.bat b/build_win_lobby_connect.bat
index 27c83e5..ddfe447 100755
--- a/build_win_lobby_connect.bat
+++ b/build_win_lobby_connect.bat
@@ -3,6 +3,7 @@ cd /d "%~dp0"
mkdir release\lobby_connect
del /Q release\lobby_connect\*
call build_set_protobuf_directories.bat
+setlocal
"%PROTOC_X86_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
call build_env_x86.bat
cl dll/rtlgenrandom.c dll/rtlgenrandom.def
@@ -10,3 +11,4 @@ cl /DNO_DISK_WRITES /DLOBBY_CONNECT /DEMU_RELEASE_BUILD /DNDEBUG /I%PROTOBUF_X86
del /Q /S release\lobby_connect\*.lib
del /Q /S release\lobby_connect\*.exp
copy Readme_lobby_connect.txt release\lobby_connect\Readme.txt
+endlocal
diff --git a/build_win_release.bat b/build_win_release.bat
index 79e7804..4470544 100755
--- a/build_win_release.bat
+++ b/build_win_release.bat
@@ -7,15 +7,19 @@ rmdir /S /Q release\lobby_connect
rmdir /S /Q release
mkdir release
call build_set_protobuf_directories.bat
+setlocal
"%PROTOC_X86_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
call build_env_x86.bat
cl dll/rtlgenrandom.c dll/rtlgenrandom.def
cl /LD /DEMU_RELEASE_BUILD /DNDEBUG /I%PROTOBUF_X86_DIRECTORY%\include\ dll/*.cpp dll/*.cc "%PROTOBUF_X86_LIBRARY%" Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib /EHsc /MP12 /Ox /link /debug:none /OUT:release\steam_api.dll
+endlocal
+setlocal
"%PROTOC_X64_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
call build_env_x64.bat
cl dll/rtlgenrandom.c dll/rtlgenrandom.def
cl /LD /DEMU_RELEASE_BUILD /DNDEBUG /I%PROTOBUF_X64_DIRECTORY%\include\ dll/*.cpp dll/*.cc "%PROTOBUF_X64_LIBRARY%" Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib /EHsc /MP12 /Ox /link /debug:none /OUT:release\steam_api64.dll
+endlocal
copy Readme_release.txt release\Readme.txt
xcopy /s files_example\* release\
call build_win_release_experimental.bat
diff --git a/build_win_release_experimental.bat b/build_win_release_experimental.bat
index 5c3ff84..b03d8a7 100755
--- a/build_win_release_experimental.bat
+++ b/build_win_release_experimental.bat
@@ -3,15 +3,19 @@ cd /d "%~dp0"
mkdir release\experimental
del /Q release\experimental\*
call build_set_protobuf_directories.bat
+setlocal
"%PROTOC_X86_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
call build_env_x86.bat
cl dll/rtlgenrandom.c dll/rtlgenrandom.def
cl /LD /DEMU_RELEASE_BUILD /DEMU_EXPERIMENTAL_BUILD /DCONTROLLER_SUPPORT /DEMU_OVERLAY /DNDEBUG /IImGui /I%PROTOBUF_X86_DIRECTORY%\include\ /Ioverlay_experimental dll/*.cpp dll/*.cc detours/*.cpp controller/gamepad.c ImGui/*.cpp ImGui/backends/imgui_impl_dx*.cpp ImGui/backends/imgui_impl_win32.cpp ImGui/backends/imgui_impl_vulkan.cpp ImGui/backends/imgui_impl_opengl3.cpp ImGui/backends/imgui_win_shader_blobs.cpp overlay_experimental/*.cpp overlay_experimental/windows/*.cpp overlay_experimental/System/*.cpp "%PROTOBUF_X86_LIBRARY%" opengl32.lib Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Winmm.lib /EHsc /MP12 /Ox /link /debug:none /OUT:release\experimental\steam_api.dll
cl /LD /DEMU_RELEASE_BUILD /DEMU_EXPERIMENTAL_BUILD /DNDEBUG steamclient.cpp /EHsc /MP4 /Ox /link /OUT:release\experimental\steamclient.dll
+endlocal
+setlocal
"%PROTOC_X64_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
call build_env_x64.bat
cl dll/rtlgenrandom.c dll/rtlgenrandom.def
cl /LD /DEMU_RELEASE_BUILD /DEMU_EXPERIMENTAL_BUILD /DCONTROLLER_SUPPORT /DEMU_OVERLAY /DNDEBUG /IImGui /I%PROTOBUF_X64_DIRECTORY%\include\ /Ioverlay_experimental dll/*.cpp dll/*.cc detours/*.cpp controller/gamepad.c ImGui/*.cpp ImGui/backends/imgui_impl_dx*.cpp ImGui/backends/imgui_impl_win32.cpp ImGui/backends/imgui_impl_vulkan.cpp ImGui/backends/imgui_impl_opengl3.cpp ImGui/backends/imgui_win_shader_blobs.cpp overlay_experimental/*.cpp overlay_experimental/windows/*.cpp overlay_experimental/System/*.cpp "%PROTOBUF_X64_LIBRARY%" opengl32.lib Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Winmm.lib /EHsc /MP12 /Ox /link /debug:none /OUT:release\experimental\steam_api64.dll
cl /LD /DEMU_RELEASE_BUILD /DEMU_EXPERIMENTAL_BUILD /DNDEBUG steamclient.cpp /EHsc /MP4 /Ox /link /OUT:release\experimental\steamclient64.dll
copy Readme_experimental.txt release\experimental\Readme.txt
+endlocal
diff --git a/build_win_release_experimental_steamclient.bat b/build_win_release_experimental_steamclient.bat
index cd55557..95c8381 100644
--- a/build_win_release_experimental_steamclient.bat
+++ b/build_win_release_experimental_steamclient.bat
@@ -3,10 +3,13 @@ cd /d "%~dp0"
mkdir release\experimental_steamclient
del /Q release\experimental_steamclient\*
call build_set_protobuf_directories.bat
+setlocal
"%PROTOC_X86_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
call build_env_x86.bat
cl dll/rtlgenrandom.c dll/rtlgenrandom.def
cl /LD /DEMU_RELEASE_BUILD /DEMU_EXPERIMENTAL_BUILD /DSTEAMCLIENT_DLL /DCONTROLLER_SUPPORT /DEMU_OVERLAY /IImGui /DNDEBUG /I%PROTOBUF_X86_DIRECTORY%\include\ /Ioverlay_experimental dll/*.cpp dll/*.cc detours/*.cpp controller/gamepad.c ImGui/*.cpp ImGui/backends/imgui_impl_dx*.cpp ImGui/backends/imgui_impl_win32.cpp ImGui/backends/imgui_impl_vulkan.cpp ImGui/backends/imgui_impl_opengl3.cpp ImGui/backends/imgui_win_shader_blobs.cpp overlay_experimental/*.cpp overlay_experimental/windows/*.cpp overlay_experimental/System/*.cpp "%PROTOBUF_X86_LIBRARY%" opengl32.lib Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Winmm.lib /EHsc /MP12 /Ox /link /debug:none /OUT:release\experimental_steamclient\steamclient.dll
+endlocal
+setlocal
"%PROTOC_X64_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
cl steamclient_loader/*.cpp advapi32.lib user32.lib /EHsc /MP12 /Ox /link /debug:none /OUT:release\experimental_steamclient\steamclient_loader.exe
copy steamclient_loader\ColdClientLoader.ini release\experimental_steamclient\
@@ -14,3 +17,4 @@ call build_env_x64.bat
cl dll/rtlgenrandom.c dll/rtlgenrandom.def
cl /LD /DEMU_RELEASE_BUILD /DEMU_EXPERIMENTAL_BUILD /DSTEAMCLIENT_DLL /DCONTROLLER_SUPPORT /DEMU_OVERLAY /IImGui /DNDEBUG /I%PROTOBUF_X64_DIRECTORY%\include\ /Ioverlay_experimental dll/*.cpp dll/*.cc detours/*.cpp controller/gamepad.c ImGui/*.cpp ImGui/backends/imgui_impl_dx*.cpp ImGui/backends/imgui_impl_win32.cpp ImGui/backends/imgui_impl_vulkan.cpp ImGui/backends/imgui_impl_opengl3.cpp ImGui/backends/imgui_win_shader_blobs.cpp overlay_experimental/*.cpp overlay_experimental/windows/*.cpp overlay_experimental/System/*.cpp "%PROTOBUF_X64_LIBRARY%" opengl32.lib Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Winmm.lib /EHsc /MP12 /Ox /link /debug:none /OUT:release\experimental_steamclient\steamclient64.dll
copy Readme_experimental_steamclient.txt release\experimental_steamclient\Readme.txt
+endlocal
\ No newline at end of file
From 98488d657058306ce31008748beba6621c89e0a2 Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Wed, 10 Jan 2024 04:29:06 -0500
Subject: [PATCH 08/67] Create windows lobby_connect debug build script.
Signed-off-by: redpolline <11156324-redpolline@users.noreply.gitlab.com>
---
build_win_debug_lobby_connect.bat | 12 ++++++++++++
1 file changed, 12 insertions(+)
create mode 100644 build_win_debug_lobby_connect.bat
diff --git a/build_win_debug_lobby_connect.bat b/build_win_debug_lobby_connect.bat
new file mode 100644
index 0000000..b87707a
--- /dev/null
+++ b/build_win_debug_lobby_connect.bat
@@ -0,0 +1,12 @@
+@echo off
+cd /d "%~dp0"
+mkdir debug\lobby_connect
+del /Q debug\lobby_connect\*
+call build_set_protobuf_directories.bat
+setlocal
+"%PROTOC_X86_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
+call build_env_x86.bat
+cl dll/rtlgenrandom.c dll/rtlgenrandom.def
+cl /DNO_DISK_WRITES /DLOBBY_CONNECT /DEMU_RELEASE_BUILD /I%PROTOBUF_X86_DIRECTORY%\include\ lobby_connect.cpp dll/*.cpp dll/*.cc "%PROTOBUF_X86_LIBRARY%" Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Comdlg32.lib /EHsc /MP12 /Ox /link /OUT:debug\lobby_connect\lobby_connect.exe
+copy Readme_lobby_connect.txt debug\lobby_connect\Readme.txt
+endlocal
From d1a0a68d4f724d4793e1acbe7bbff8c910b8cb07 Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Wed, 10 Jan 2024 04:30:17 -0500
Subject: [PATCH 09/67] Add relay daemon mode to lobby_connect.
This (along with the existing custom_broadcasts support) allows for users on different read: _routed_ subnets to see and connect to each other's games.
To use this mode:
Build lobby_connect and run it with the "-d" argument.
Create the custom_broadcasts.txt file in the steam_settings folder next to steam_api.dll / steam_api64.dll and put the IP address of the host running lobby_connect in it.
Run games.
Note: This should even work with existing installations, _provided_ that at least one of them creates the custom_broadcasts.txt file as described above.
(This is because existing installations use broadcast packets to establish new connections, forwarding all of their knowledge to each other.
Thus having at least one host on the current subnet configured in this new way turns it into a "proxy" for the other hosts.)
Caveat: This will _NOT_ work if NAT is involved. This is due to the lack of NAT traversal support in the emu.
(I.e. The lobby_connect daemon will get the info from the NAT'ed hosts and forward it to the others, but hosts outside the NAT won't be able to connect.)
Signed-off-by: redpolline <11156324-redpolline@users.noreply.gitlab.com>
---
lobby_connect.cpp | 152 ++++++++++++++++++++++++++--------------------
1 file changed, 86 insertions(+), 66 deletions(-)
diff --git a/lobby_connect.cpp b/lobby_connect.cpp
index 36f3327..3af6dad 100644
--- a/lobby_connect.cpp
+++ b/lobby_connect.cpp
@@ -32,93 +32,113 @@
#else
#endif
-int main() {
+int main(int argc, char ** argv) {
+ bool broadcast_relay_daemon = false;
+
+ if (argc > 1) {
+ for (int x = 1; x < argc; x++) {
+ if (strcmp(argv[x], "-d") == 0) {
+ broadcast_relay_daemon = true;
+ }
+ }
+ }
+
if (SteamAPI_Init()) {
//Set appid to: LOBBY_CONNECT_APPID
SteamAPI_RestartAppIfNecessary(LOBBY_CONNECT_APPID);
- std::cout << "This is a program to find lobbies and run the game with lobby connect parameters" << std::endl;
- std::cout << "Api initialized, ";
+ if (broadcast_relay_daemon) {
+ std::cout << "Running in relay daemon mode. Press Ctrl+C to exit...." << std::endl;
+ std::cout.flush();
+
+ while (1) {
+ SteamAPI_RunCallbacks();
+ std::this_thread::sleep_for(std::chrono::milliseconds(200));
+ }
+ } else {
+ std::cout << "This is a program to find lobbies and run the game with lobby connect parameters" << std::endl;
+ std::cout << "Api initialized, ";
top:
- std::cout << "waiting a few seconds for connections:" << std::endl;
- for (int i = 0; i < 10; ++i) {
- SteamAPI_RunCallbacks();
- std::this_thread::sleep_for(std::chrono::milliseconds(200));
- }
+ std::cout << "waiting a few seconds for connections:" << std::endl;
+ for (int i = 0; i < 10; ++i) {
+ SteamAPI_RunCallbacks();
+ std::this_thread::sleep_for(std::chrono::milliseconds(200));
+ }
- int friend_count = SteamFriends()->GetFriendCount(k_EFriendFlagAll);
- std::cout << "People on the network: " << friend_count << std::endl;
- for (int i = 0; i < friend_count; ++i) {
- CSteamID id = SteamFriends()->GetFriendByIndex(i, k_EFriendFlagAll);
- const char *name = SteamFriends()->GetFriendPersonaName(id);
+ int friend_count = SteamFriends()->GetFriendCount(k_EFriendFlagAll);
+ std::cout << "People on the network: " << friend_count << std::endl;
+ for (int i = 0; i < friend_count; ++i) {
+ CSteamID id = SteamFriends()->GetFriendByIndex(i, k_EFriendFlagAll);
+ const char *name = SteamFriends()->GetFriendPersonaName(id);
- FriendGameInfo_t friend_info = {};
- SteamFriends()->GetFriendGamePlayed(id, &friend_info);
- std::cout << name << " is playing: " << friend_info.m_gameID.AppID() << std::endl;
- }
+ FriendGameInfo_t friend_info = {};
+ SteamFriends()->GetFriendGamePlayed(id, &friend_info);
+ std::cout << name << " is playing: " << friend_info.m_gameID.AppID() << std::endl;
+ }
- std::cout << std::endl << "--------------Menu-------------" << std::endl << "\tappid\tname\tcommand line" << std::endl;
+ std::cout << std::endl << "--------------Menu-------------" << std::endl << "\tappid\tname\tcommand line" << std::endl;
- std::vector arguments;
- for (int i = 0; i < friend_count; ++i) {
- CSteamID id = SteamFriends()->GetFriendByIndex(i, k_EFriendFlagAll);
- const char *name = SteamFriends()->GetFriendPersonaName(id);
- const char *connect = SteamFriends()->GetFriendRichPresence( id, "connect");
- FriendGameInfo_t friend_info = {};
- SteamFriends()->GetFriendGamePlayed(id, &friend_info);
+ std::vector arguments;
+ for (int i = 0; i < friend_count; ++i) {
+ CSteamID id = SteamFriends()->GetFriendByIndex(i, k_EFriendFlagAll);
+ const char *name = SteamFriends()->GetFriendPersonaName(id);
+ const char *connect = SteamFriends()->GetFriendRichPresence( id, "connect");
+ FriendGameInfo_t friend_info = {};
+ SteamFriends()->GetFriendGamePlayed(id, &friend_info);
- if (strlen(connect) > 0) {
- std::cout << arguments.size() << "\t" << friend_info.m_gameID.AppID() << "\t" << name << "\t" << connect << std::endl;
- arguments.push_back(connect);
- } else {
- if (friend_info.m_steamIDLobby != k_steamIDNil) {
- std::string connect = "+connect_lobby " + std::to_string(friend_info.m_steamIDLobby.ConvertToUint64());
+ if (strlen(connect) > 0) {
std::cout << arguments.size() << "\t" << friend_info.m_gameID.AppID() << "\t" << name << "\t" << connect << std::endl;
arguments.push_back(connect);
+ } else {
+ if (friend_info.m_steamIDLobby != k_steamIDNil) {
+ std::string connect = "+connect_lobby " + std::to_string(friend_info.m_steamIDLobby.ConvertToUint64());
+ std::cout << arguments.size() << "\t" << friend_info.m_gameID.AppID() << "\t" << name << "\t" << connect << std::endl;
+ arguments.push_back(connect);
+ }
}
}
- }
- std::cout << arguments.size() << ": Retry." << std::endl;
- std::cout << std::endl << "Enter the number corresponding to your choice then press Enter." << std::endl;
- unsigned int choice;
- std::cin >> choice;
+ std::cout << arguments.size() << ": Retry." << std::endl;
+ std::cout << std::endl << "Enter the number corresponding to your choice then press Enter." << std::endl;
+ unsigned int choice;
+ std::cin >> choice;
- if (choice >= arguments.size()) goto top;
+ if (choice >= arguments.size()) goto top;
#ifdef _WIN32
- std::cout << "starting the game with: " << arguments[choice] << std::endl << "Please select the game exe" << std::endl;
+ std::cout << "starting the game with: " << arguments[choice] << std::endl << "Please select the game exe" << std::endl;
- OPENFILENAMEA ofn;
- char szFileName[MAX_PATH] = "";
- ZeroMemory(&ofn, sizeof(ofn));
- ofn.lStructSize = sizeof(ofn);
- ofn.hwndOwner = 0;
- ofn.lpstrFilter = "Exe Files (*.exe)\0*.exe\0All Files (*.*)\0*.*\0";
- ofn.lpstrFile = szFileName;
- ofn.nMaxFile = MAX_PATH;
- ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
- ofn.lpstrDefExt = "txt";
- if(GetOpenFileNameA(&ofn))
- {
- std::string filename = szFileName;
- filename = "\"" + filename + "\" " + arguments[choice];
- std::cout << filename << std::endl;
- STARTUPINFOA lpStartupInfo;
- PROCESS_INFORMATION lpProcessInfo;
+ OPENFILENAMEA ofn;
+ char szFileName[MAX_PATH] = "";
+ ZeroMemory(&ofn, sizeof(ofn));
+ ofn.lStructSize = sizeof(ofn);
+ ofn.hwndOwner = 0;
+ ofn.lpstrFilter = "Exe Files (*.exe)\0*.exe\0All Files (*.*)\0*.*\0";
+ ofn.lpstrFile = szFileName;
+ ofn.nMaxFile = MAX_PATH;
+ ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
+ ofn.lpstrDefExt = "txt";
+ if(GetOpenFileNameA(&ofn))
+ {
+ std::string filename = szFileName;
+ filename = "\"" + filename + "\" " + arguments[choice];
+ std::cout << filename << std::endl;
+ STARTUPINFOA lpStartupInfo;
+ PROCESS_INFORMATION lpProcessInfo;
- ZeroMemory( &lpStartupInfo, sizeof( lpStartupInfo ) );
- lpStartupInfo.cb = sizeof( lpStartupInfo );
- ZeroMemory( &lpProcessInfo, sizeof( lpProcessInfo ) );
+ ZeroMemory( &lpStartupInfo, sizeof( lpStartupInfo ) );
+ lpStartupInfo.cb = sizeof( lpStartupInfo );
+ ZeroMemory( &lpProcessInfo, sizeof( lpProcessInfo ) );
- CreateProcessA( NULL,
- const_cast(filename.c_str()), NULL, NULL,
- NULL, NULL, NULL, NULL,
- &lpStartupInfo,
- &lpProcessInfo
- );
- }
+ CreateProcessA( NULL,
+ const_cast(filename.c_str()), NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ &lpStartupInfo,
+ &lpProcessInfo
+ );
+ }
#else
- std::cout << "Please launch the game with these arguments: " << arguments[choice] << std::endl;
+ std::cout << "Please launch the game with these arguments: " << arguments[choice] << std::endl;
#endif
+ }
}
}
From d78ab8e8a55b9f7d0a003756e58b2febc6795602 Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Wed, 10 Jan 2024 04:45:37 -0500
Subject: [PATCH 10/67] Add missing echo off to
build_win_debug_experimental_steamclient.bat.
Signed-off-by: redpolline <11156324-redpolline@users.noreply.gitlab.com>
---
build_win_debug_experimental_steamclient.bat | 1 +
1 file changed, 1 insertion(+)
diff --git a/build_win_debug_experimental_steamclient.bat b/build_win_debug_experimental_steamclient.bat
index 4e7517b..8555e69 100644
--- a/build_win_debug_experimental_steamclient.bat
+++ b/build_win_debug_experimental_steamclient.bat
@@ -1,3 +1,4 @@
+@echo off
cd /d "%~dp0"
mkdir debug
From 8f212b82cadce80e9c7ba9b0411ab2daa1401ead Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Wed, 10 Jan 2024 05:00:43 -0500
Subject: [PATCH 11/67] Generate PDB files for the debug builds.
Allows for better debugging with Windows debuggers.
Signed-off-by: redpolline <11156324-redpolline@users.noreply.gitlab.com>
---
build_win_debug_experimental.bat | 10 +++++-----
build_win_debug_experimental_steamclient.bat | 4 ++--
build_win_debug_lobby_connect.bat | 2 +-
3 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/build_win_debug_experimental.bat b/build_win_debug_experimental.bat
index f92957b..ba56b41 100755
--- a/build_win_debug_experimental.bat
+++ b/build_win_debug_experimental.bat
@@ -9,14 +9,14 @@ setlocal
"%PROTOC_X86_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
call build_env_x86.bat
cl dll/rtlgenrandom.c dll/rtlgenrandom.def
-cl /Z7 /LD /IImGui /I%PROTOBUF_X86_DIRECTORY%\include\ /DEMU_EXPERIMENTAL_BUILD /DCONTROLLER_SUPPORT /DEMU_OVERLAY /Ioverlay_experimental dll/*.cpp dll/*.cc detours/*.cpp controller/gamepad.c ImGui/*.cpp ImGui/backends/imgui_impl_dx*.cpp ImGui/backends/imgui_impl_win32.cpp ImGui/backends/imgui_impl_vulkan.cpp ImGui/backends/imgui_impl_opengl3.cpp ImGui/backends/imgui_win_shader_blobs.cpp overlay_experimental/*.cpp overlay_experimental/windows/*.cpp overlay_experimental/System/*.cpp "%PROTOBUF_X86_LIBRARY%" opengl32.lib Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Winmm.lib /EHsc /MP12 /link /OUT:debug\experimental\steam_api.dll
-cl /LD steamclient.cpp /EHsc /MP12 /link /OUT:debug\experimental\steamclient.dll
+cl /LD /IImGui /I%PROTOBUF_X86_DIRECTORY%\include\ /DEMU_EXPERIMENTAL_BUILD /DCONTROLLER_SUPPORT /DEMU_OVERLAY /Ioverlay_experimental dll/*.cpp dll/*.cc detours/*.cpp controller/gamepad.c ImGui/*.cpp ImGui/backends/imgui_impl_dx*.cpp ImGui/backends/imgui_impl_win32.cpp ImGui/backends/imgui_impl_vulkan.cpp ImGui/backends/imgui_impl_opengl3.cpp ImGui/backends/imgui_win_shader_blobs.cpp overlay_experimental/*.cpp overlay_experimental/windows/*.cpp overlay_experimental/System/*.cpp "%PROTOBUF_X86_LIBRARY%" opengl32.lib Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Winmm.lib /EHsc /MP12 /DDEBUG:FULL /Zi /Fd:.\debug\experimental\steam_api.pdb /link /OUT:debug\experimental\steam_api.dll
+cl /LD steamclient.cpp /EHsc /MP12 /DDEBUG:FULL /Zi /Fd:.\debug\experimental\steamclient.pdb /link /OUT:debug\experimental\steamclient.dll
endlocal
setlocal
"%PROTOC_X64_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
call build_env_x64.bat
cl dll/rtlgenrandom.c dll/rtlgenrandom.def
-cl /Z7 /LD /IImGui /I%PROTOBUF_X64_DIRECTORY%\include\ /DEMU_EXPERIMENTAL_BUILD /DCONTROLLER_SUPPORT /DEMU_OVERLAY /Ioverlay_experimental dll/*.cpp dll/*.cc detours/*.cpp controller/gamepad.c ImGui/*.cpp ImGui/backends/imgui_impl_dx*.cpp ImGui/backends/imgui_impl_win32.cpp ImGui/backends/imgui_impl_vulkan.cpp ImGui/backends/imgui_impl_opengl3.cpp ImGui/backends/imgui_win_shader_blobs.cpp overlay_experimental/*.cpp overlay_experimental/windows/*.cpp overlay_experimental/System/*.cpp "%PROTOBUF_X64_LIBRARY%" opengl32.lib Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Winmm.lib /EHsc /MP12 /link /OUT:debug\experimental\steam_api64.dll
-cl /LD steamclient.cpp /EHsc /MP12 /link /OUT:debug\experimental\steamclient64.dll
-endlocal
\ No newline at end of file
+cl /LD /IImGui /I%PROTOBUF_X64_DIRECTORY%\include\ /DEMU_EXPERIMENTAL_BUILD /DCONTROLLER_SUPPORT /DEMU_OVERLAY /Ioverlay_experimental dll/*.cpp dll/*.cc detours/*.cpp controller/gamepad.c ImGui/*.cpp ImGui/backends/imgui_impl_dx*.cpp ImGui/backends/imgui_impl_win32.cpp ImGui/backends/imgui_impl_vulkan.cpp ImGui/backends/imgui_impl_opengl3.cpp ImGui/backends/imgui_win_shader_blobs.cpp overlay_experimental/*.cpp overlay_experimental/windows/*.cpp overlay_experimental/System/*.cpp "%PROTOBUF_X64_LIBRARY%" opengl32.lib Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Winmm.lib /EHsc /MP12 /DDEBUG:FULL /Zi /Fd:.\debug\experimental\steam_api64.pdb /link /OUT:debug\experimental\steam_api64.dll
+cl /LD steamclient.cpp /EHsc /MP12 /DDEBUG:FULL /Zi /Fd:.\debug\experimental\steamclient64.pdb /link /OUT:debug\experimental\steamclient64.dll
+endlocal
diff --git a/build_win_debug_experimental_steamclient.bat b/build_win_debug_experimental_steamclient.bat
index 8555e69..2bca8e2 100644
--- a/build_win_debug_experimental_steamclient.bat
+++ b/build_win_debug_experimental_steamclient.bat
@@ -9,10 +9,10 @@ setlocal
"%PROTOC_X86_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
call build_env_x86.bat
cl dll/rtlgenrandom.c dll/rtlgenrandom.def
-cl /LD /IImGui /I%PROTOBUF_X86_DIRECTORY%\include\ /DSTEAMCLIENT_DLL /DCONTROLLER_SUPPORT /DEMU_EXPERIMENTAL_BUILD /DEMU_OVERLAY /Ioverlay_experimental dll/*.cpp dll/*.cc detours/*.cpp controller/gamepad.c ImGui/*.cpp ImGui/backends/imgui_impl_dx*.cpp ImGui/backends/imgui_impl_win32.cpp ImGui/backends/imgui_impl_vulkan.cpp ImGui/backends/imgui_impl_opengl3.cpp ImGui/backends/imgui_win_shader_blobs.cpp overlay_experimental/*.cpp overlay_experimental/windows/*.cpp overlay_experimental/System/*.cpp "%PROTOBUF_X86_LIBRARY%" opengl32.lib Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Winmm.lib /EHsc /MP12 /link /OUT:debug\experimental_steamclient\steamclient.dll
+cl /LD /IImGui /I%PROTOBUF_X86_DIRECTORY%\include\ /DSTEAMCLIENT_DLL /DCONTROLLER_SUPPORT /DEMU_EXPERIMENTAL_BUILD /DEMU_OVERLAY /Ioverlay_experimental dll/*.cpp dll/*.cc detours/*.cpp controller/gamepad.c ImGui/*.cpp ImGui/backends/imgui_impl_dx*.cpp ImGui/backends/imgui_impl_win32.cpp ImGui/backends/imgui_impl_vulkan.cpp ImGui/backends/imgui_impl_opengl3.cpp ImGui/backends/imgui_win_shader_blobs.cpp overlay_experimental/*.cpp overlay_experimental/windows/*.cpp overlay_experimental/System/*.cpp "%PROTOBUF_X86_LIBRARY%" opengl32.lib Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Winmm.lib /EHsc /MP12 /DDEBUG:FULL /Zi /Fd:.\debug\experimental_steamclient\steamclient.pdb /link /OUT:debug\experimental_steamclient\steamclient.dll
endlocal
setlocal
call build_env_x64.bat
cl dll/rtlgenrandom.c dll/rtlgenrandom.def
-cl /LD /IImGui /I%PROTOBUF_X64_DIRECTORY%\include\ /DSTEAMCLIENT_DLL /DCONTROLLER_SUPPORT /DEMU_EXPERIMENTAL_BUILD /DEMU_OVERLAY /Ioverlay_experimental dll/*.cpp dll/*.cc detours/*.cpp controller/gamepad.c ImGui/*.cpp ImGui/backends/imgui_impl_dx*.cpp ImGui/backends/imgui_impl_win32.cpp ImGui/backends/imgui_impl_vulkan.cpp ImGui/backends/imgui_impl_opengl3.cpp ImGui/backends/imgui_win_shader_blobs.cpp overlay_experimental/*.cpp overlay_experimental/windows/*.cpp overlay_experimental/System/*.cpp "%PROTOBUF_X64_LIBRARY%" opengl32.lib Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Winmm.lib /EHsc /MP12 /link /OUT:debug\experimental_steamclient\steamclient64.dll
+cl /LD /IImGui /I%PROTOBUF_X64_DIRECTORY%\include\ /DSTEAMCLIENT_DLL /DCONTROLLER_SUPPORT /DEMU_EXPERIMENTAL_BUILD /DEMU_OVERLAY /Ioverlay_experimental dll/*.cpp dll/*.cc detours/*.cpp controller/gamepad.c ImGui/*.cpp ImGui/backends/imgui_impl_dx*.cpp ImGui/backends/imgui_impl_win32.cpp ImGui/backends/imgui_impl_vulkan.cpp ImGui/backends/imgui_impl_opengl3.cpp ImGui/backends/imgui_win_shader_blobs.cpp overlay_experimental/*.cpp overlay_experimental/windows/*.cpp overlay_experimental/System/*.cpp "%PROTOBUF_X64_LIBRARY%" opengl32.lib Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Winmm.lib /EHsc /MP12 /DDEBUG:FULL /Zi /Fd:.\debug\experimental_steamclient\steamclient64.pdb /link /OUT:debug\experimental_steamclient\steamclient64.dll
endlocal
diff --git a/build_win_debug_lobby_connect.bat b/build_win_debug_lobby_connect.bat
index b87707a..cdea074 100644
--- a/build_win_debug_lobby_connect.bat
+++ b/build_win_debug_lobby_connect.bat
@@ -7,6 +7,6 @@ setlocal
"%PROTOC_X86_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
call build_env_x86.bat
cl dll/rtlgenrandom.c dll/rtlgenrandom.def
-cl /DNO_DISK_WRITES /DLOBBY_CONNECT /DEMU_RELEASE_BUILD /I%PROTOBUF_X86_DIRECTORY%\include\ lobby_connect.cpp dll/*.cpp dll/*.cc "%PROTOBUF_X86_LIBRARY%" Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Comdlg32.lib /EHsc /MP12 /Ox /link /OUT:debug\lobby_connect\lobby_connect.exe
+cl /DNO_DISK_WRITES /DLOBBY_CONNECT /DEMU_RELEASE_BUILD /I%PROTOBUF_X86_DIRECTORY%\include\ lobby_connect.cpp dll/*.cpp dll/*.cc "%PROTOBUF_X86_LIBRARY%" Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Comdlg32.lib /EHsc /MP12 /Ox /DDEBUG:FULL /Zi /Fd:.\debug\lobby_connect\lobby_connect.pdb /link /OUT:debug\lobby_connect\lobby_connect.exe
copy Readme_lobby_connect.txt debug\lobby_connect\Readme.txt
endlocal
From a2c9f9230f220c6c99b93c34d9e1311bae0e004e Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Wed, 10 Jan 2024 05:04:28 -0500
Subject: [PATCH 12/67] Improve steam_masterserver_updater stub.
This creates a new "custom_master_server.txt" file that can be used to pre-seed a master server list.
This also allows for steam apps to manipulate the master server list in memory.
I.e. This implements:
Steam_Masterserver_Updater::AddMasterServer()
Steam_Masterserver_Updater::RemoveMasterServer()
Steam_Masterserver_Updater::GetNumMasterServers()
Steam_Masterserver_Updater::GetMasterServerAddress()
Signed-off-by: redpolline <11156324-redpolline@users.noreply.gitlab.com>
---
dll/settings.h | 3 +
dll/settings_parser.cpp | 7 ++
dll/steam_masterserver_updater.h | 87 ++++++++++++++++++-
.../custom_master_server.EXAMPLE.txt | 2 +
4 files changed, 97 insertions(+), 2 deletions(-)
create mode 100644 files_example/steam_settings.EXAMPLE/custom_master_server.EXAMPLE.txt
diff --git a/dll/settings.h b/dll/settings.h
index a7b2aa9..aeb8b49 100644
--- a/dll/settings.h
+++ b/dll/settings.h
@@ -132,6 +132,9 @@ public:
//custom broadcasts
std::set custom_broadcasts;
+ //custom master server
+ std::set custom_master_server;
+
//stats
std::map getStats() { return stats; }
void setStatDefiniton(std::string name, struct Stat_config stat_config) {stats[ascii_to_lowercase(name)] = stat_config; }
diff --git a/dll/settings_parser.cpp b/dll/settings_parser.cpp
index 22dad2e..ef34316 100644
--- a/dll/settings_parser.cpp
+++ b/dll/settings_parser.cpp
@@ -211,6 +211,11 @@ uint32 create_localstorage_settings(Settings **settings_client_out, Settings **s
load_custom_broadcasts(local_storage->get_global_settings_path() + "custom_broadcasts.txt", custom_broadcasts);
load_custom_broadcasts(Local_Storage::get_game_settings_path() + "custom_broadcasts.txt", custom_broadcasts);
+ // Custom master server
+ std::set custom_master_server;
+ load_custom_broadcasts(local_storage->get_global_settings_path() + "custom_master_server.txt", custom_master_server);
+ load_custom_broadcasts(Local_Storage::get_game_settings_path() + "custom_master_server.txt", custom_master_server);
+
// Acount name
char name[32] = {};
if (local_storage->get_data_settings("account_name.txt", name, sizeof(name) - 1) <= 0) {
@@ -359,6 +364,8 @@ uint32 create_localstorage_settings(Settings **settings_client_out, Settings **s
settings_server->set_port(port);
settings_client->custom_broadcasts = custom_broadcasts;
settings_server->custom_broadcasts = custom_broadcasts;
+ settings_client->custom_master_server = custom_master_server;
+ settings_server->custom_master_server = custom_master_server;
settings_client->disable_networking = disable_networking;
settings_server->disable_networking = disable_networking;
settings_client->disable_overlay = disable_overlay;
diff --git a/dll/steam_masterserver_updater.h b/dll/steam_masterserver_updater.h
index d55e63e..d17ccd8 100644
--- a/dll/steam_masterserver_updater.h
+++ b/dll/steam_masterserver_updater.h
@@ -173,12 +173,64 @@ void ForceHeartbeat()
bool AddMasterServer( const char *pServerAddress )
{
PRINT_DEBUG("Steam_Masterserver_Updater::AddMasterServer\n");
+
+ IP_PORT addr;
+
+ if (pServerAddress)
+ {
+ addr.ip = (uint32)*pServerAddress;
+ if (pServerAddress[(sizeof(uint32))] != 0)
+ {
+ addr.port = (uint16)*(pServerAddress + sizeof(uint32));
+ }
+ else
+ {
+ addr.port = 27016;
+ }
+ PRINT_DEBUG("Steam_Masterserver_Updater::AddMasterServer pServerAddress IP: %d, PORT: %d", addr.ip, addr.port);
+ this->settings->custom_master_server.insert(addr);
+ }
+
return true;
}
bool RemoveMasterServer( const char *pServerAddress )
{
PRINT_DEBUG("Steam_Masterserver_Updater::RemoveMasterServer\n");
+
+ std::set::iterator iter;
+ IP_PORT addr;
+ IP_PORT list;
+
+ if (pServerAddress)
+ {
+ addr.ip = (uint32)*pServerAddress;
+ if (pServerAddress[(sizeof(uint32))] != 0)
+ {
+ addr.port = (uint16)*(pServerAddress + sizeof(uint32));
+ }
+ else
+ {
+ addr.port = 27016;
+ }
+ PRINT_DEBUG("Steam_Masterserver_Updater::RemoveMasterServer pServerAddress IP: %d, PORT: %d", addr.ip, addr.port);
+
+ iter = this->settings->custom_master_server.begin();
+ while (iter != this->settings->custom_master_server.end())
+ {
+ list = (*iter);
+ if (addr.ip == list.ip &&
+ (addr.port == list.port || (list.port == 0 && addr.port == 27016)))
+ {
+ iter = this->settings->custom_master_server.erase(iter);
+ }
+ else
+ {
+ iter++;
+ }
+ }
+ }
+
return true;
}
@@ -186,7 +238,7 @@ bool RemoveMasterServer( const char *pServerAddress )
int GetNumMasterServers()
{
PRINT_DEBUG("Steam_Masterserver_Updater::GetNumMasterServers\n");
- return 0;
+ return this->settings->custom_master_server.size();
}
@@ -194,7 +246,38 @@ int GetNumMasterServers()
int GetMasterServerAddress( int iServer, char *pOut, int outBufferSize )
{
PRINT_DEBUG("Steam_Masterserver_Updater::GetMasterServerAddress\n");
- return 0;
+
+ size_t written_bytes = 0;
+ char * byte_cpy = NULL;
+ std::set::iterator iter;
+ IP_PORT addr;
+
+ if (pOut && outBufferSize >= sizeof(uint32) && this->settings->custom_master_server.size() > 0)
+ {
+ iter = this->settings->custom_master_server.begin();
+ while (written_bytes < outBufferSize && iter != this->settings->custom_master_server.end())
+ {
+ addr = (*iter);
+ byte_cpy = (char*)&(addr.ip);
+ for (size_t x = 0; x < sizeof(addr.ip) && written_bytes < outBufferSize; x++)
+ {
+ memcpy(pOut + x, byte_cpy + x, 1);
+ written_bytes++;
+ }
+ if (addr.port != 0 && addr.port != 27016) // Default updater port.
+ {
+ byte_cpy = (char*)&(addr.port);
+ for (size_t x = 0; x < sizeof(addr.port) && written_bytes < outBufferSize; x++)
+ {
+ memcpy(pOut + x, byte_cpy + x, 1);
+ written_bytes++;
+ }
+ }
+ iter++;
+ }
+ }
+
+ return written_bytes;
}
diff --git a/files_example/steam_settings.EXAMPLE/custom_master_server.EXAMPLE.txt b/files_example/steam_settings.EXAMPLE/custom_master_server.EXAMPLE.txt
new file mode 100644
index 0000000..2837580
--- /dev/null
+++ b/files_example/steam_settings.EXAMPLE/custom_master_server.EXAMPLE.txt
@@ -0,0 +1,2 @@
+192.168.7.99
+removethis.test.domain.com
From ef5c4731b4a58a41dfc5b677d1cc41631b055cb8 Mon Sep 17 00:00:00 2001
From: ayaka
Date: Sun, 29 Aug 2021 16:05:17 +0800
Subject: [PATCH 13/67] dll/wrap: fix build for glibc 2.33
I don't think I need the step that converting to legacy struct.
Signed-off-by: ayaka
---
dll/common_includes.h | 3 +-
dll/wrap.cpp | 67 +++++++++++++++++++++++++++++++++++++++----
2 files changed, 63 insertions(+), 7 deletions(-)
diff --git a/dll/common_includes.h b/dll/common_includes.h
index 5de14c4..3b43545 100644
--- a/dll/common_includes.h
+++ b/dll/common_includes.h
@@ -112,7 +112,6 @@ inline void reset_LastError()
#include
#include
#include
- #include
#include
#include
@@ -205,4 +204,4 @@ inline std::string ascii_to_lowercase(std::string data) {
#define LOBBY_CONNECT_APPID ((uint32)-2)
-#endif//__INCLUDED_COMMON_INCLUDES__
\ No newline at end of file
+#endif//__INCLUDED_COMMON_INCLUDES__
diff --git a/dll/wrap.cpp b/dll/wrap.cpp
index 50defc7..7cabf7c 100644
--- a/dll/wrap.cpp
+++ b/dll/wrap.cpp
@@ -25,6 +25,7 @@
// Nothing to be done here
#else
#define STEAM_API_FUNCTIONS_IMPL
+
#include "base.h"
#include "dll.h"
@@ -34,6 +35,26 @@
const char *STEAM_PATH;
size_t STEAM_PATH_SIZE;
+#ifndef __x86_64__
+# define _STAT_VER_LINUX_OLD 1
+# define _STAT_VER_KERNEL 1
+# define _STAT_VER_SVR4 2
+# define _STAT_VER_LINUX 3
+# define _MKNOD_VER_LINUX 1
+# define _MKNOD_VER_SVR4 2
+#else
+# define _STAT_VER_KERNEL 0
+# define _STAT_VER_LINUX 1
+# define _MKNOD_VER_LINUX 0
+#endif
+#define _STAT_VER _STAT_VER_LINUX
+#define _MKNOD_VER _MKNOD_VER_LINUX
+
+/* From kernel_stat.h It help me save some condition */
+#define XSTAT_IS_XSTAT64 1
+#define STATFS_IS_STATFS64 __STATFS_MATCHES_STATFS64
+#define STAT_IS_KERNEL_STAT 1
+
// Returns a '/' terminated absolute path to the steam folder in user's home,
// root is returned if env home is not set
const char *get_steam_path()
@@ -290,7 +311,16 @@ STEAMAPI_API int __wrap_access(const char *path, int mode)
STEAMAPI_API int __wrap___xstat(int ver, const char * path, struct stat * stat_buf)
{
const char *path_lowercased = lowercase_path(path, false, false);
- int result = __xstat(ver, path_lowercased, stat_buf);
+ int result;
+
+ switch (ver) {
+ case _STAT_VER_KERNEL:
+ result = stat(path_lowercased, stat_buf);
+ break;
+ default:
+ result = EINVAL;
+ }
+
if (path_lowercased != path) {
free((void *)path_lowercased);
}
@@ -305,7 +335,16 @@ STEAMAPI_API int __wrap_stat(const char * path, struct stat * stat_buf)
STEAMAPI_API int __wrap___lxstat(int ver, const char * path, struct stat * stat_buf)
{
const char *path_lowercased = lowercase_path(path, false, false);
- int result = __lxstat(ver, path_lowercased, stat_buf);
+ int result;
+
+ switch (ver) {
+ case _STAT_VER_KERNEL:
+ result = lstat(path_lowercased, stat_buf);
+ break;
+ default:
+ result = EINVAL;
+ }
+
if (path_lowercased != path) {
free((void *)path_lowercased);
}
@@ -350,7 +389,16 @@ STEAMAPI_API DIR *__wrap_opendir(const char *path)
STEAMAPI_API int __wrap___xstat64(int ver, const char *path, struct stat64 *stat_buf)
{
const char *path_lowercased = lowercase_path(path, false, false);
- int result = __xstat64(ver, path_lowercased, stat_buf);
+ int result;
+
+ switch (ver) {
+ case _STAT_VER_KERNEL:
+ result = stat64(path_lowercased, stat_buf);
+ break;
+ default:
+ result = EINVAL;
+ }
+
if (path_lowercased != path) {
free((void *)path_lowercased);
}
@@ -360,7 +408,16 @@ STEAMAPI_API int __wrap___xstat64(int ver, const char *path, struct stat64 *stat
STEAMAPI_API int __wrap___lxstat64(int ver, const char *path, struct stat64 *stat_buf)
{
const char *path_lowercased = lowercase_path(path, false, false);
- int result = __lxstat64(ver, path_lowercased, stat_buf);
+ int result;
+
+ switch (ver) {
+ case _STAT_VER_KERNEL:
+ result = lstat64(path_lowercased, stat_buf);
+ break;
+ default:
+ result = EINVAL;
+ }
+
if (path_lowercased != path) {
free((void *)path_lowercased);
}
@@ -448,7 +505,7 @@ STEAMAPI_API int __wrap_link(const char *path1, const char *path2)
STEAMAPI_API int __wrap_mknod(const char *path, mode_t mode, dev_t dev)
{
const char *path_lowercased = lowercase_path(path, true, true);
- int result = __xmknod(1, path_lowercased, mode, &dev);
+ int result = mknod(path_lowercased, mode, dev);
if (path_lowercased != path) {
free((void *)path_lowercased);
}
From b75f3241007e33e00fe28328f0803ad5f3978abf Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Thu, 6 Jun 2024 08:30:59 -0400
Subject: [PATCH 14/67] Fix build scripts.
Fix list:
- Make cmd not choke on recursive calls to build_env_x*.bat.
- Create build directories and move build output there instead of
polluting the root of the source tree.
- Make proper debug builds with pdb output.
- Make proper x64 builds of lobby_connect, and steamclient_loader. (lobby_connect_x64.exe, and steamclient_loader_x64.exe)
- Rename x86 build of lobby_connect.exe to lobby_connect_x86.exe.
- Rename x86 build of steamclient_loader.exe to steamclient_loader_x86.exe.
- Make proper distrib directories. (I.e. ///.)
---
.gitignore | 35 ++++++++++---------
build_env_x64.bat | 12 +++++++
build_env_x86.bat | 13 ++++++-
build_win_debug_experimental.bat | 34 +++++++++++++-----
build_win_debug_experimental_steamclient.bat | 30 ++++++++++++----
build_win_debug_lobby_connect.bat | 21 ++++++++---
build_win_find_interfaces.bat | 19 +++++++---
build_win_lobby_connect.bat | 21 +++++++----
build_win_release.bat | 34 ++++++++++++------
build_win_release_experimental.bat | 32 ++++++++++++-----
...d_win_release_experimental_steamclient.bat | 34 +++++++++++++-----
11 files changed, 211 insertions(+), 74 deletions(-)
diff --git a/.gitignore b/.gitignore
index 47acc83..788c645 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,17 +1,18 @@
-.vs/*
-.vscode/*
-*.bin
-*.o
-net.pb.*
-*steam_api*
-release/*
-/build*/
-*.obj
-/dll/net.pb.cc
-/dll/net.pb.h
-base.exp
-base.lib
-rtlgenrandom*
-steamclient.exp
-steamclient.lib
-out/*
+.vs/*
+.vscode/*
+*.bin
+*.o
+net.pb.*
+*steam_api*
+release/*
+debug/*
+/build*/
+*.obj
+/dll/net.pb.cc
+/dll/net.pb.h
+base.exp
+base.lib
+rtlgenrandom*
+steamclient.exp
+steamclient.lib
+out/*
diff --git a/build_env_x64.bat b/build_env_x64.bat
index 35b701b..21c181d 100755
--- a/build_env_x64.bat
+++ b/build_env_x64.bat
@@ -12,6 +12,8 @@ if exist "%VS_Base_Path%\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Bu
if exist "%VS_Base_Path%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat" goto vs2022
if exist "%VS_Base_Path%\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvars64.bat" goto vs2022_bt
if exist ".\sdk_standalone\set_vars64.bat" goto gitlabci
+if exist "vsinstallloc.txt" goto readloc
+if exist "%VS_Base_Path%\Microsoft Visual Studio\Installer\vswhere.exe" goto wherevs
:vs2022
call "%VS_Base_Path%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat"
@@ -44,4 +46,14 @@ goto batend
:gitlabci
call ".\sdk_standalone\set_vars64.bat"
goto batend
+
+:wherevs
+call "%VS_Base_Path%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -property installationPath > vsinstallloc.txt
+goto readloc
+
+:readloc
+set /p VS_LOCAL= vsinstallloc.txt
+goto readloc
+
+:readloc
+set /p VS_LOCAL=
Date: Fri, 31 Jan 2025 02:06:41 +0000
Subject: [PATCH 15/67] Update .gitlab-ci.yml file to skip building the PDBs.
(CI throws errors and skips building the PE files.)
---
.gitlab-ci.yml | 10 ++++++++--
generate_build_win_bat.py | 7 ++++++-
2 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index c158841..98989b5 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -69,15 +69,21 @@ build_windows:
- 7za x protobuf_x86-windows-static.7z -oprotobuf_x86-windows-static
- 7za x protobuf_x64-windows-static.7z -oprotobuf_x64-windows-static
- 7za x sdk_standalone.7z -osdk_standalone
- - DLL_FILES="$(ls dll/*.cpp | tr "\n" " ")"; sed "s|dll/\*.cpp|$DLL_FILES|g" -i *.bat
- - DLL_FILES="$(ls dll/*.proto | tr "\n" " " | sed "s/.proto/.pb.cc/g")"; sed "s|dll/\*.cc|$DLL_FILES|g" -i *.bat
+ - DLL_FILES="$(ls dll/*.cpp | tr "\n" " " | tr "/" "\\\\")"; sed "s|dll/\*.cpp|$DLL_FILES|g" -i *.bat
+ - DLL_FILES="$(ls dll/*.proto | tr "\n" " " | tr "/" "\\\\" | sed "s/.proto/.pb.cc/g")"; sed "s|dll/\*.cc|$DLL_FILES|g" -i *.bat
- sed "s| /MP12 | /MP4 |g" -i *.bat
+ # CI can't produce PDBs. Throws a bunch of errors, and skips building the PEs.
+ - sed "s| /DDEBUG\:FULL | |g" -i *.bat
+ # Turn on echo.
+ - sed "s|echo off|echo on|g" -i *.bat
- python generate_build_win_bat.py
- export WINEDEBUG=-all
- wine cmd /c build_win_release_test.bat
+ - cp build_win_release_test.bat release/build_win_release_test.bat
artifacts:
paths:
- release/
+ - debug/
expire_in: 1 day
build_cmake_linux:
diff --git a/generate_build_win_bat.py b/generate_build_win_bat.py
index f24b6bc..9e3ef47 100644
--- a/generate_build_win_bat.py
+++ b/generate_build_win_bat.py
@@ -32,6 +32,7 @@ includes_64 = list(map(lambda a: '/I{}'.format(a), ["%PROTOBUF_X64_DIRECTORY%\\i
debug_build_args = []
release_build_args = ["/DEMU_RELEASE_BUILD", "/DNDEBUG"]
steamclient_build_args = ["/DSTEAMCLIENT_DLL"]
+lobby_connect_args = ["/DNO_DISK_WRITES", "/DLOBBY_CONNECT"]
experimental_build_args = ["/DEMU_EXPERIMENTAL_BUILD", "/DCONTROLLER_SUPPORT", "/DEMU_OVERLAY"]
steamclient_experimental_build_args = experimental_build_args + steamclient_build_args
@@ -62,6 +63,7 @@ mkdir release\experimental
mkdir release\experimental_steamclient
mkdir release\debug_experimental
mkdir release\debug_experimental_steamclient
+mkdir release\lobby_connect
call build_set_protobuf_directories.bat
"""
@@ -81,7 +83,8 @@ xcopy /s files_example\* release\\
copy Readme_experimental.txt release\experimental\Readme.txt
copy Readme_debug.txt release\debug_experimental\Readme.txt
copy steamclient_loader\ColdClientLoader.ini release\experimental_steamclient\\
-call build_win_lobby_connect.bat
+REM call build_win_lobby_connect.bat
+copy Readme_lobby_connect.txt release\lobby_connect\Readme.txt
call build_win_find_interfaces.bat
"""
@@ -114,6 +117,8 @@ def generate_common(include_arch, linker_arch, steam_api_name, steamclient_name)
out += generate_common(includes_32, linker_32, "steam_api.dll", "steamclient.dll")
+out += cl_line_exe(files_from_dir("./", "lobby_connect.cpp") + files_from_dir("dll", "flat.cpp") + files_from_dir("dll", "dll.cpp") + lobby_connect_args + normal_build_args + release_build_args + includes_32 + proto_deps + steam_deps + normal_linker_libs + ["Comdlg32.lib", "user32.lib"], linker_32 + ["/debug:none", "/OUT:release\lobby_connect\lobby_connect.exe"])
+
out += cl_line_exe(files_from_dir("steamclient_loader", ".cpp") + ["advapi32.lib", "user32.lib"] + normal_build_args, ["/debug:none", "/OUT:release\experimental_steamclient\steamclient_loader.exe"])
out += head_64bit
From 74d22df42e6055becd39f8773cfdf9e3cd509dda Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Tue, 4 Feb 2025 18:28:11 -0500
Subject: [PATCH 16/67] Fix CI to use BAT files only for win build.
For consistency have the CI use the same build path as
the end-user builds.
Use where.exe from wine-10.0.
CI's version is a stub. Use one that actually works, until the CI gets
updated.
Also, fix broken RtlGenRandom by importing ADVAPI32's GetUserNameW(),
and calling GetModuleHandleW() / GetProcAddress() for SystemFunction032().
Instead of trying to use a fake import lib.
Bonus: Can now use the host system's username as the default for the
steam user name instead of "Noob".
("Noob" is still used as the fallback if this call fails, or the host
system's username is invalid.)
---
.gitlab-ci.yml | 26 +-
build_set_protobuf_directories.bat | 11 +-
build_win_debug_experimental.bat | 37 +-
build_win_debug_experimental_steamclient.bat | 147 ++++++-
build_win_debug_lobby_connect.bat | 47 +-
build_win_find_interfaces.bat | 39 +-
build_win_lobby_connect.bat | 47 +-
build_win_release.bat | 41 +-
build_win_release_experimental.bat | 36 +-
...d_win_release_experimental_steamclient.bat | 145 ++++++-
dll/base.cpp | 31 +-
dll/rtlgenrandom.c | 4 -
dll/rtlgenrandom.def | 3 -
dll/settings_parser.cpp | 34 +-
generate_all_deps.bat | 57 +++
generate_build_win.bat | 406 ++++++++++++++++++
generate_build_win_bat.py | 132 ------
17 files changed, 926 insertions(+), 317 deletions(-)
delete mode 100644 dll/rtlgenrandom.c
delete mode 100644 dll/rtlgenrandom.def
create mode 100644 generate_all_deps.bat
create mode 100644 generate_build_win.bat
delete mode 100644 generate_build_win_bat.py
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 98989b5..1a7612e 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -59,27 +59,29 @@ build_windows:
image: fedora:35
script:
- - dnf -y install wine wget p7zip sed dos2unix python
+ - dnf -y install wine wget p7zip sed dos2unix python cpio
- unix2dos *.txt
- unix2dos files_example/*.txt files_example/*/*.txt
- sed -i 's/..\\vcpkg\\installed\\/.\\protobuf_/g' build_set_protobuf_directories.bat
- wget 'https://gitlab.com/Mr_Goldberg/goldberg_emulator/uploads/48db8f434a193aae872279dc4f5dde6a/sdk_standalone.7z'
- wget 'https://gitlab.com/Mr_Goldberg/goldberg_emulator/uploads/0119304e030098b4821d73170fe52084/protobuf_x64-windows-static.7z'
- wget 'https://gitlab.com/Mr_Goldberg/goldberg_emulator/uploads/4185a97ab363ddc1859127e59ec68581/protobuf_x86-windows-static.7z'
+ # Ancient CI version of wine doesn't support the where.exe cmd. (It's a stub.) Use the version from wine-10.0.
+ - wget 'https://dl.fedoraproject.org/pub/fedora/linux/updates/41/Everything/x86_64/Packages/w/wine-core-10.0-1.fc41.i686.rpm'
+ - mkdir wine
+ - echo './usr/lib/wine/i386-windows/where.exe' > extract.txt; rpm2cpio wine-core-10.0-1.fc41.i686.rpm | cpio -ivdE extract.txt; rm -f extract.txt
+ - /usr/bin/mv -f ./usr/lib/wine/i386-windows/where.exe wine/; rm -rf ./usr/
+ - /usr/bin/cp -f wine/where.exe /usr/lib/wine/i386-windows/where.exe; /usr/bin/cp -f wine/where.exe /usr/lib64/wine/x86_64-windows/where.exe
- 7za x protobuf_x86-windows-static.7z -oprotobuf_x86-windows-static
- 7za x protobuf_x64-windows-static.7z -oprotobuf_x64-windows-static
- 7za x sdk_standalone.7z -osdk_standalone
- - DLL_FILES="$(ls dll/*.cpp | tr "\n" " " | tr "/" "\\\\")"; sed "s|dll/\*.cpp|$DLL_FILES|g" -i *.bat
- - DLL_FILES="$(ls dll/*.proto | tr "\n" " " | tr "/" "\\\\" | sed "s/.proto/.pb.cc/g")"; sed "s|dll/\*.cc|$DLL_FILES|g" -i *.bat
- sed "s| /MP12 | /MP4 |g" -i *.bat
# CI can't produce PDBs. Throws a bunch of errors, and skips building the PEs.
- - sed "s| /DDEBUG\:FULL | |g" -i *.bat
- # Turn on echo.
- - sed "s|echo off|echo on|g" -i *.bat
- - python generate_build_win_bat.py
+ - touch CI_BUILD.TAG
- export WINEDEBUG=-all
- - wine cmd /c build_win_release_test.bat
- - cp build_win_release_test.bat release/build_win_release_test.bat
+ - WINEPATH=$PWD/wine wine cmd /c build_win_debug_experimental_steamclient.bat 8
+ - WINEPATH=$PWD/wine wine cmd /c build_win_release.bat 8
+
artifacts:
paths:
- release/
@@ -162,9 +164,9 @@ deploy_all:
- mv linux release/
- shopt -s extglob
- rm -rf .g*
- - rm -rf !(release)
- - mv release/* ./
- - rm -rf release
+ - rm -rf !(release|debug)
+# - mv release/* ./
+# - rm -rf release
- echo $CI_JOB_ID > job_id
- tree
artifacts:
diff --git a/build_set_protobuf_directories.bat b/build_set_protobuf_directories.bat
index fb3e63b..8bd16a6 100755
--- a/build_set_protobuf_directories.bat
+++ b/build_set_protobuf_directories.bat
@@ -1,7 +1,14 @@
@echo off
cd /d "%~dp0"
-SET PROTOBUF_X86_DIRECTORY=..\vcpkg\installed\x86-windows-static
-SET PROTOBUF_X64_DIRECTORY=..\vcpkg\installed\x64-windows-static
+
+SET TEST_A=%cd%
+REM CI doesn't like this var expansion of "%cd%\".
+cd ..\vcpkg\installed\x86-windows-static
+SET PROTOBUF_X86_DIRECTORY=%cd%
+cd %TEST_A%
+cd ..\vcpkg\installed\x64-windows-static
+SET PROTOBUF_X64_DIRECTORY=%cd%
+cd %TEST_A%
rem location of protoc in protobuf directories:
SET PROTOC_X86_EXE=%PROTOBUF_X86_DIRECTORY%\tools\protobuf\protoc.exe
diff --git a/build_win_debug_experimental.bat b/build_win_debug_experimental.bat
index 10ebb89..7cbc3c8 100755
--- a/build_win_debug_experimental.bat
+++ b/build_win_debug_experimental.bat
@@ -1,38 +1,9 @@
@echo off
cd /d "%~dp0"
-IF NOT EXIST build ( mkdir build )
-IF NOT EXIST build\experimental ( mkdir build\experimental )
-IF NOT EXIST build\experimental\debug ( mkdir build\experimental\debug )
-IF NOT EXIST build\experimental\debug\x86 ( mkdir build\experimental\debug\x86 )
-IF NOT EXIST build\experimental\debug\x64 ( mkdir build\experimental\debug\x64 )
-IF EXIST build\experimental\debug\x86\*.* ( DEL /F /S /Q build\experimental\debug\x86\*.* )
-IF EXIST build\experimental\debug\x64\*.* ( DEL /F /S /Q build\experimental\debug\x64\*.* )
+IF NOT "%1" == "" ( SET JOB_COUNT=%~1 )
-IF NOT EXIST debug ( mkdir debug )
-IF NOT EXIST debug\experimental ( mkdir debug\experimental )
-IF EXIST debug\experimental\*.* ( DEL /F /S /Q debug\experimental\*.* )
+SET SKIP_EXPERIMENTAL_STEAMCLIENT_BUILD=1
+SET SKIP_STEAMCLIENT_LOADER=1
-call build_set_protobuf_directories.bat
-
-setlocal
-"%PROTOC_X86_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
-call build_env_x86.bat
-SET OLD_DIR=%cd%
-cd build\experimental\debug\x86
-cl %OLD_DIR%/dll/rtlgenrandom.c %OLD_DIR%/dll/rtlgenrandom.def
-cl /LD /I%OLD_DIR%/ImGui /I%OLD_DIR%/%PROTOBUF_X86_DIRECTORY%\include\ /DEMU_EXPERIMENTAL_BUILD /DCONTROLLER_SUPPORT /DEMU_OVERLAY /I%OLD_DIR%/overlay_experimental %OLD_DIR%/dll/*.cpp %OLD_DIR%/dll/*.cc %OLD_DIR%/detours/*.cpp %OLD_DIR%/controller/gamepad.c %OLD_DIR%/ImGui/*.cpp %OLD_DIR%/ImGui/backends/imgui_impl_dx*.cpp %OLD_DIR%/ImGui/backends/imgui_impl_win32.cpp %OLD_DIR%/ImGui/backends/imgui_impl_vulkan.cpp %OLD_DIR%/ImGui/backends/imgui_impl_opengl3.cpp %OLD_DIR%/ImGui/backends/imgui_win_shader_blobs.cpp %OLD_DIR%/overlay_experimental/*.cpp %OLD_DIR%/overlay_experimental/windows/*.cpp %OLD_DIR%/overlay_experimental/System/*.cpp "%OLD_DIR%/%PROTOBUF_X86_LIBRARY%" opengl32.lib Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Winmm.lib /EHsc /MP12 /DDEBUG:FULL /Zi /Fd:%OLD_DIR%\debug\experimental\steam_api.pdb /link /OUT:%OLD_DIR%\debug\experimental\steam_api.dll
-cl /LD %OLD_DIR%/steamclient.cpp /EHsc /MP12 /DDEBUG:FULL /Zi /Fd:%OLD_DIR%\debug\experimental\steamclient.pdb /link /OUT:%OLD_DIR%\debug\experimental\steamclient.dll
-cd %OLD_DIR%
-endlocal
-
-setlocal
-"%PROTOC_X64_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
-call build_env_x64.bat
-SET OLD_DIR=%cd%
-cd build\experimental\debug\x64
-cl %OLD_DIR%/dll/rtlgenrandom.c %OLD_DIR%/dll/rtlgenrandom.def
-cl /LD /I%OLD_DIR%/ImGui /I%OLD_DIR%/%PROTOBUF_X64_DIRECTORY%\include\ /DEMU_EXPERIMENTAL_BUILD /DCONTROLLER_SUPPORT /DEMU_OVERLAY /I%OLD_DIR%/overlay_experimental %OLD_DIR%/dll/*.cpp %OLD_DIR%/dll/*.cc %OLD_DIR%/detours/*.cpp %OLD_DIR%/controller/gamepad.c %OLD_DIR%/ImGui/*.cpp %OLD_DIR%/ImGui/backends/imgui_impl_dx*.cpp %OLD_DIR%/ImGui/backends/imgui_impl_win32.cpp %OLD_DIR%/ImGui/backends/imgui_impl_vulkan.cpp %OLD_DIR%/ImGui/backends/imgui_impl_opengl3.cpp %OLD_DIR%/ImGui/backends/imgui_win_shader_blobs.cpp %OLD_DIR%/overlay_experimental/*.cpp %OLD_DIR%/overlay_experimental/windows/*.cpp %OLD_DIR%/overlay_experimental/System/*.cpp "%OLD_DIR%/%PROTOBUF_X64_LIBRARY%" opengl32.lib Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Winmm.lib /EHsc /MP12 /DDEBUG:FULL /Zi /Fd:%OLD_DIR%\debug\experimental\steam_api64.pdb /link /OUT:%OLD_DIR%\debug\experimental\steam_api64.dll
-cl /LD %OLD_DIR%/steamclient.cpp /EHsc /MP12 /DDEBUG:FULL /Zi /Fd:%OLD_DIR%\debug\experimental\steamclient64.pdb /link /OUT:%OLD_DIR%\debug\experimental\steamclient64.dll
-cd %OLD_DIR%
-endlocal
+call build_win_debug_experimental_steamclient.bat
diff --git a/build_win_debug_experimental_steamclient.bat b/build_win_debug_experimental_steamclient.bat
index 32da89a..85d7f8d 100644
--- a/build_win_debug_experimental_steamclient.bat
+++ b/build_win_debug_experimental_steamclient.bat
@@ -1,36 +1,141 @@
@echo off
cd /d "%~dp0"
-IF NOT EXIST build ( mkdir build )
-IF NOT EXIST build\experimental_steamclient ( mkdir build\experimental_steamclient )
-IF NOT EXIST build\experimental_steamclient\debug ( mkdir build\experimental_steamclient\debug )
-IF NOT EXIST build\experimental_steamclient\debug\x86 ( mkdir build\experimental_steamclient\debug\x86 )
-IF NOT EXIST build\experimental_steamclient\debug\x64 ( mkdir build\experimental_steamclient\debug\x64 )
-IF EXIST build\experimental_steamclient\debug\x86\*.* ( DEL /F /S /Q build\experimental_steamclient\debug\x86\*.* )
-IF EXIST build\experimental_steamclient\debug\x64\*.* ( DEL /F /S /Q build\experimental_steamclient\debug\x64\*.* )
+SET OLD_DIR=%cd%
+
+IF NOT "%1" == "" ( SET JOB_COUNT=%~1 )
+
+IF NOT DEFINED BUILT_ALL_DEPS ( call generate_all_deps.bat )
+
+IF EXIST build\experimental\steamclient\debug\x86\*.* ( DEL /F /S /Q build\experimental\steamclient\debug\x86\*.* )
+IF EXIST build\experimental\steamclient\debug\x64\*.* ( DEL /F /S /Q build\experimental\steamclient\debug\x64\*.* )
-IF NOT EXIST debug ( mkdir debug )
-IF NOT EXIST debug\experimental_steamclient ( mkdir debug\experimental_steamclient )
IF EXIST debug\experimental_steamclient\*.* ( DEL /F /S /Q debug\experimental_steamclient\*.* )
-call build_set_protobuf_directories.bat
-
setlocal
+
+IF DEFINED SKIP_X86 GOTO LK_X64
+
"%PROTOC_X86_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
call build_env_x86.bat
-SET OLD_DIR=%cd%
-cd build\experimental_steamclient\debug\x86
-cl %OLD_DIR%/dll/rtlgenrandom.c %OLD_DIR%/dll/rtlgenrandom.def
-cl /LD /I%OLD_DIR%/ImGui /I%OLD_DIR%/%PROTOBUF_X86_DIRECTORY%\include\ /DSTEAMCLIENT_DLL /DCONTROLLER_SUPPORT /DEMU_EXPERIMENTAL_BUILD /DEMU_OVERLAY /I%OLD_DIR%/overlay_experimental %OLD_DIR%/dll/*.cpp %OLD_DIR%/dll/*.cc %OLD_DIR%/detours/*.cpp %OLD_DIR%/controller/gamepad.c %OLD_DIR%/ImGui/*.cpp %OLD_DIR%/ImGui/backends/imgui_impl_dx*.cpp %OLD_DIR%/ImGui/backends/imgui_impl_win32.cpp %OLD_DIR%/ImGui/backends/imgui_impl_vulkan.cpp %OLD_DIR%/ImGui/backends/imgui_impl_opengl3.cpp %OLD_DIR%/ImGui/backends/imgui_win_shader_blobs.cpp %OLD_DIR%/overlay_experimental/*.cpp %OLD_DIR%/overlay_experimental/windows/*.cpp %OLD_DIR%/overlay_experimental/System/*.cpp "%OLD_DIR%/%PROTOBUF_X86_LIBRARY%" opengl32.lib Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Winmm.lib /EHsc /MP12 /DDEBUG:FULL /Zi /Fd:%OLD_DIR%\debug\experimental_steamclient\steamclient.pdb /link /OUT:%OLD_DIR%\debug\experimental_steamclient\steamclient.dll
-cl %OLD_DIR%/steamclient_loader/*.cpp advapi32.lib user32.lib /EHsc /MP12 /Ox /DDEBUG:FULL /Zi /Fd:%OLD_DIR%\debug\experimental_steamclient\steamclient_loader_x32.pdb /link /OUT:%OLD_DIR%\debug\experimental_steamclient\steamclient_loader_x32.exe
+
+REM Non-STEAMCLIENT_DLL debug sc_deps.
+cd "%OLD_DIR%\build\experimental_steamclient\debug\x86\sc_deps"
+cl /c @%CDS_DIR%\DEBUG.BLD @%CDS_DIR%\PROTOBUF_X86.BLD @%CDS_DIR%\SC_DEPS.BLD
+IF EXIST %CDS_DIR%\DEBUG_SC_DEPS_X86.LKS ( DEL /F /Q %CDS_DIR%\DEBUG_SC_DEPS_X86.LKS )
+where "*.obj" > %CDS_DIR%\DEBUG_SC_DEPS_X86.LKS
+
+IF DEFINED SKIP_EXPERIMENTAL_BUILD GOTO LK_EXP_STEAMCLIENT_DLL_X86
+
+REM Link Non-STEAMCLIENT_DLL debug steam_api.dll.
+cd "%OLD_DIR%\build\experimental\debug\x86\"
+IF EXIST %CDS_DIR%\DEBUG_STEAMAPI_NON_X86.LKS ( DEL /F /Q %CDS_DIR%\DEBUG_STEAMAPI_NON_X86.LKS )
+echo /link /OUT:%OLD_DIR%\debug\experimental\steam_api.dll > %CDS_DIR%\DEBUG_STEAMAPI_NON_X86.LKS
+IF NOT EXIST %OLD_DIR%\CI_BUILD.TAG ( echo /link /PDB:%OLD_DIR%\debug\experimental\steam_api.pdb >> %CDS_DIR%\DEBUG_STEAMAPI_NON_X86.LKS )
+cl /LD @%CDS_DIR%\DEBUG.LKS @%CDS_DIR%\PROTOBUF_X86.LKS @%CDS_DIR%\EXPERIMENTAL.BLD @%CDS_DIR%\EXPERIMENTAL.LKS @%CDS_DIR%\DEBUG_ALL_DEPS_X86.LKS @%CDS_DIR%\DEBUG_SC_DEPS_X86.LKS @%CDS_DIR%\DEBUG_STEAMAPI_NON_X86.LKS
+
+:LK_EXP_STEAMCLIENT_DLL_X86
+
+IF DEFINED SKIP_EXPERIMENTAL_STEAMCLIENT_BUILD GOTO LK_STEAMCLIENT_DLL_X86
+
+REM Link STEAMCLIENT_DLL debug steamclient.dll
+cd "%OLD_DIR%\build\experimental_steamclient\debug\x86"
+IF EXIST %CDS_DIR%\DEBUG_STEAMCLIENT_X86.LKS ( DEL /F /Q %CDS_DIR%\DEBUG_STEAMCLIENT_X86.LKS )
+echo /link /OUT:%OLD_DIR%\debug\experimental_steamclient\steamclient.dll > %CDS_DIR%\DEBUG_STEAMCLIENT_X86.LKS
+IF NOT EXIST %OLD_DIR%\CI_BUILD.TAG ( echo /link /PDB:%OLD_DIR%\debug\experimental_steamclient\steamclient.pdb >> %CDS_DIR%\DEBUG_STEAMCLIENT_X86.LKS )
+cl /LD @%CDS_DIR%\DEBUG.LKS @%CDS_DIR%\PROTOBUF_X86.LKS @%CDS_DIR%\EXPERIMENTAL_STEAMCLIENT.LKS @%CDS_DIR%\DEBUG_ALL_DEPS_X86.LKS @%CDS_DIR%\DEBUG_SC_DEPS_X86.LKS @%CDS_DIR%\DEBUG_STEAMCLIENT_X86.LKS
+
+:LK_STEAMCLIENT_DLL_X86
+
+IF DEFINED SKIP_EXPERIMENTAL_BUILD GOTO LK_STEAMCLIENT_LOADER_X86
+
+REM Link Non-STEAMCLIENT_DLL debug steamclient.dll.
+cd "%OLD_DIR%\build\experimental\debug\x86\"
+IF EXIST %CDS_DIR%\DEBUG_STEAMCLIENT_NON_X86.LKS ( DEL /F /Q %CDS_DIR%\DEBUG_STEAMCLIENT_NON_X86.LKS )
+echo /link /OUT:%OLD_DIR%\debug\experimental\steamclient.dll > %CDS_DIR%\DEBUG_STEAMCLIENT_NON_X86.LKS
+IF NOT EXIST %OLD_DIR%\CI_BUILD.TAG ( echo /link /PDB:%OLD_DIR%\debug\experimental\steamclient.pdb >> %CDS_DIR%\DEBUG_STEAMCLIENT_NON_X86.LKS )
+cl /LD @%CDS_DIR%\DEBUG.LKS @%CDS_DIR%\STEAMCLIENT.BLD @%CDS_DIR%\DEBUG_STEAMCLIENT_NON_X86.LKS
+
+:LK_STEAMCLIENT_LOADER_X86
+
+IF DEFINED SKIP_STEAMCLIENT_LOADER GOTO LK_X64
+
+REM Build steamclient_loader debug x86.
+cd "%OLD_DIR%\build\experimental_steamclient\steamclient_loader\debug\x86"
+cl /c @%CDS_DIR%\DEBUG.BLD @%CDS_DIR%\STEAMCLIENT_LOADER.BLD
+IF EXIST %CDS_DIR%\DEBUG_STEAMCLIENT_LOADER_X86.LKS ( DEL /F /Q %CDS_DIR%\DEBUG_STEAMCLIENT_LOADER_X86.LKS )
+where "*.obj" > %CDS_DIR%\DEBUG_STEAMCLIENT_LOADER_X86.LKS
+echo /link /OUT:%OLD_DIR%\debug\experimental_steamclient\steamclient_loader_x32.exe >> %CDS_DIR%\DEBUG_STEAMCLIENT_LOADER_X86.LKS
+IF NOT EXIST %OLD_DIR%\CI_BUILD.TAG ( echo /link /PDB:%OLD_DIR%\debug\experimental_steamclient\steamclient_loader_x32.pdb >> %CDS_DIR%\DEBUG_STEAMCLIENT_LOADER_X86.LKS )
+cl @%CDS_DIR%\DEBUG.LKS @%CDS_DIR%\STEAMCLIENT_LOADER.LKS @%CDS_DIR%\DEBUG_STEAMCLIENT_LOADER_X86.LKS
cd %OLD_DIR%
+
+:LK_X64
+
endlocal
+
setlocal
+
+IF DEFINED SKIP_X64 GOTO LK_END
+
+"%PROTOC_X64_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
call build_env_x64.bat
-SET OLD_DIR=%cd%
-cd build\experimental_steamclient\debug\x64
-cl %OLD_DIR%/dll/rtlgenrandom.c %OLD_DIR%/dll/rtlgenrandom.def
-cl /LD /I%OLD_DIR%/ImGui /I%OLD_DIR%/%PROTOBUF_X64_DIRECTORY%\include\ /DSTEAMCLIENT_DLL /DCONTROLLER_SUPPORT /DEMU_EXPERIMENTAL_BUILD /DEMU_OVERLAY /I%OLD_DIR%/overlay_experimental %OLD_DIR%/dll/*.cpp %OLD_DIR%/dll/*.cc %OLD_DIR%/detours/*.cpp %OLD_DIR%/controller/gamepad.c %OLD_DIR%/ImGui/*.cpp %OLD_DIR%/ImGui/backends/imgui_impl_dx*.cpp %OLD_DIR%/ImGui/backends/imgui_impl_win32.cpp %OLD_DIR%/ImGui/backends/imgui_impl_vulkan.cpp %OLD_DIR%/ImGui/backends/imgui_impl_opengl3.cpp %OLD_DIR%/ImGui/backends/imgui_win_shader_blobs.cpp %OLD_DIR%/overlay_experimental/*.cpp %OLD_DIR%/overlay_experimental/windows/*.cpp %OLD_DIR%/overlay_experimental/System/*.cpp "%OLD_DIR%/%PROTOBUF_X64_LIBRARY%" opengl32.lib Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Winmm.lib /EHsc /MP12 /DDEBUG:FULL /Zi /Fd:%OLD_DIR%\debug\experimental_steamclient\steamclient64.pdb /link /OUT:%OLD_DIR%\debug\experimental_steamclient\steamclient64.dll
-cl %OLD_DIR%/steamclient_loader/*.cpp advapi32.lib user32.lib /EHsc /MP12 /Ox /DDEBUG:FULL /Zi /Fd:%OLD_DIR%\debug\experimental_steamclient\steamclient_loader_x64.pdb /link /OUT:%OLD_DIR%\debug\experimental_steamclient\steamclient_loader_x64.exe
+
+REM Non-STEAMCLIENT_DLL debug sc_deps.
+cd "%OLD_DIR%\build\experimental_steamclient\debug\x64\sc_deps"
+cl /c @%CDS_DIR%\DEBUG.BLD @%CDS_DIR%\PROTOBUF_X64.BLD @%CDS_DIR%\SC_DEPS.BLD
+IF EXIST %CDS_DIR%\DEBUG_SC_DEPS_X64.LKS ( DEL /F /Q %CDS_DIR%\DEBUG_SC_DEPS_X64.LKS )
+where "*.obj" > %CDS_DIR%\DEBUG_SC_DEPS_X64.LKS
+
+IF DEFINED SKIP_EXPERIMENTAL_BUILD GOTO LK_EXP_STEAMCLIENT_DLL_X64
+
+REM Link Non-STEAMCLIENT_DLL debug steam_api64.dll.
+cd "%OLD_DIR%\build\experimental\debug\x64\"
+IF EXIST %CDS_DIR%\DEBUG_STEAMAPI_NON_X64.LKS ( DEL /F /Q %CDS_DIR%\DEBUG_STEAMAPI_NON_X64.LKS )
+echo /link /OUT:%OLD_DIR%\debug\experimental\steam_api64.dll > %CDS_DIR%\DEBUG_STEAMAPI_NON_X64.LKS
+IF NOT EXIST %OLD_DIR%\CI_BUILD.TAG ( echo /link /PDB:%OLD_DIR%\debug\experimental\steam_api64.pdb >> %CDS_DIR%\DEBUG_STEAMAPI_NON_X64.LKS )
+cl /LD @%CDS_DIR%\DEBUG.LKS @%CDS_DIR%\PROTOBUF_X64.LKS @%CDS_DIR%\EXPERIMENTAL.BLD @%CDS_DIR%\EXPERIMENTAL.LKS @%CDS_DIR%\DEBUG_ALL_DEPS_X64.LKS @%CDS_DIR%\DEBUG_SC_DEPS_X64.LKS @%CDS_DIR%\DEBUG_STEAMAPI_NON_X64.LKS
+
+:LK_EXP_STEAMCLIENT_DLL_X64
+
+IF DEFINED SKIP_EXPERIMENTAL_STEAMCLIENT_BUILD GOTO LK_STEAMCLIENT_DLL_X64
+
+REM Link STEAMCLIENT_DLL debug steamclient64.dll
+cd "%OLD_DIR%\build\experimental_steamclient\debug\x64"
+IF EXIST %CDS_DIR%\DEBUG_STEAMCLIENT_X64.LKS ( DEL /F /Q %CDS_DIR%\DEBUG_STEAMCLIENT_X64.LKS )
+echo /link /OUT:%OLD_DIR%\debug\experimental_steamclient\steamclient64.dll > %CDS_DIR%\DEBUG_STEAMCLIENT_X64.LKS
+IF NOT EXIST %OLD_DIR%\CI_BUILD.TAG ( echo /link /PDB:%OLD_DIR%\debug\experimental_steamclient\steamclient64.pdb >> %CDS_DIR%\DEBUG_STEAMCLIENT_X64.LKS )
+cl /LD @%CDS_DIR%\DEBUG.LKS @%CDS_DIR%\PROTOBUF_X64.LKS @%CDS_DIR%\EXPERIMENTAL_STEAMCLIENT.LKS @%CDS_DIR%\DEBUG_ALL_DEPS_X64.LKS @%CDS_DIR%\DEBUG_SC_DEPS_X64.LKS @%CDS_DIR%\DEBUG_STEAMCLIENT_X64.LKS
+
+:LK_STEAMCLIENT_DLL_X64
+
+IF DEFINED SKIP_EXPERIMENTAL_BUILD GOTO LK_STEAMCLIENT_LOADER_X64
+
+REM Link Non-STEAMCLIENT_DLL debug steamclient64.dll.
+cd "%OLD_DIR%\build\experimental\debug\x64\"
+IF EXIST %CDS_DIR%\DEBUG_STEAMCLIENT_NON_X64.LKS ( DEL /F /Q %CDS_DIR%\DEBUG_STEAMCLIENT_NON_X64.LKS )
+echo /link /OUT:%OLD_DIR%\debug\experimental\steamclient64.dll > %CDS_DIR%\DEBUG_STEAMCLIENT_NON_X64.LKS
+IF NOT EXIST %OLD_DIR%\CI_BUILD.TAG ( echo /link /PDB:%OLD_DIR%\debug\experimental\steamclient64.pdb >> %CDS_DIR%\DEBUG_STEAMCLIENT_NON_X64.LKS )
+cl /LD @%CDS_DIR%\DEBUG.LKS @%CDS_DIR%\STEAMCLIENT.BLD @%CDS_DIR%\DEBUG_STEAMCLIENT_NON_X64.LKS
+
+:LK_STEAMCLIENT_LOADER_X64
+
+IF DEFINED SKIP_STEAMCLIENT_LOADER GOTO LK_END
+
+REM Build steamclient_loader debug x64.
+cd "%OLD_DIR%\build\experimental_steamclient\steamclient_loader\debug\x64"
+cl /c @%CDS_DIR%\DEBUG.BLD @%CDS_DIR%\STEAMCLIENT_LOADER.BLD
+IF EXIST %CDS_DIR%\DEBUG_STEAMCLIENT_LOADER_X64.LKS ( DEL /F /Q %CDS_DIR%\DEBUG_STEAMCLIENT_LOADER_X64.LKS )
+where "*.obj" > %CDS_DIR%\DEBUG_STEAMCLIENT_LOADER_X64.LKS
+echo /link /OUT:%OLD_DIR%\debug\experimental_steamclient\steamclient_loader_x64.exe >> %CDS_DIR%\DEBUG_STEAMCLIENT_LOADER_X64.LKS
+IF NOT EXIST %OLD_DIR%\CI_BUILD.TAG ( echo /link /PDB:%OLD_DIR%\debug\experimental_steamclient\steamclient_loader_x64.pdb >> %CDS_DIR%\DEBUG_STEAMCLIENT_LOADER_X64.LKS )
+cl @%CDS_DIR%\DEBUG.LKS @%CDS_DIR%\STEAMCLIENT_LOADER.LKS @%CDS_DIR%\DEBUG_STEAMCLIENT_LOADER_X64.LKS
cd %OLD_DIR%
+
+:LK_END
+
endlocal
+
+copy Readme_experimental.txt debug\experimental\Readme.txt
+copy steamclient_loader\ColdClientLoader.ini debug\experimental_steamclient\
+copy Readme_experimental_steamclient.txt debug\experimental_steamclient\Readme.txt
diff --git a/build_win_debug_lobby_connect.bat b/build_win_debug_lobby_connect.bat
index 0ae8792..7ad250e 100644
--- a/build_win_debug_lobby_connect.bat
+++ b/build_win_debug_lobby_connect.bat
@@ -1,25 +1,46 @@
@echo off
cd /d "%~dp0"
-IF NOT EXIST build ( mkdir build )
-IF NOT EXIST build\debug ( mkdir build\debug )
-IF NOT EXIST build\debug\lobby_connect ( mkdir build\debug\lobby_connect )
-IF NOT EXIST build\debug\lobby_connect\x86 ( mkdir build\debug\lobby_connect\x86 )
+SET OLD_DIR=%cd%
+
+IF NOT "%1" == "" ( SET JOB_COUNT=%~1 )
+
+IF NOT DEFINED BUILT_ALL_DEPS ( call generate_all_deps.bat )
+
IF EXIST build\debug\lobby_connect\x86\*.* ( DEL /F /S /Q build\debug\lobby_connect\x86\*.* )
+IF EXIST build\debug\lobby_connect\x64\*.* ( DEL /F /S /Q build\debug\lobby_connect\x64\*.* )
-IF NOT EXIST debug ( mkdir debug )
-IF NOT EXIST debug\lobby_connect ( mkdir debug\lobby_connect )
IF EXIST debug\lobby_connect\*.* ( DEL /F /S /Q debug\lobby_connect\*.* )
-call build_set_protobuf_directories.bat
-
setlocal
"%PROTOC_X86_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
call build_env_x86.bat
-SET OLD_DIR=%cd%
-cd build\debug\lobby_connect\x86
-cl %OLD_DIR%/dll/rtlgenrandom.c %OLD_DIR%/dll/rtlgenrandom.def
-cl /DNO_DISK_WRITES /DLOBBY_CONNECT /DEMU_RELEASE_BUILD /I%OLD_DIR%/%PROTOBUF_X86_DIRECTORY%\include\ %OLD_DIR%/lobby_connect.cpp %OLD_DIR%/dll/*.cpp %OLD_DIR%/dll/*.cc "%OLD_DIR%/%PROTOBUF_X86_LIBRARY%" Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Comdlg32.lib /EHsc /MP12 /Ox /DDEBUG:FULL /Zi /Fd:%OLD_DIR%\debug\lobby_connect\lobby_connect.pdb /link /OUT:%OLD_DIR%\debug\lobby_connect\lobby_connect.exe
+cd %OLD_DIR%\build\lobby_connect\debug\x86
+
+cl /c @%CDS_DIR%\DEBUG.BLD @%CDS_DIR%\PROTOBUF_X86.BLD @%CDS_DIR%\LOBBY_CONNECT.BLD
+IF EXIST %CDS_DIR%\DEBUG_LOBBY_CONNECT_X86.LKS ( DEL /F /Q %CDS_DIR%\DEBUG_LOBBY_CONNECT_X86.LKS )
+where "*.obj" > %CDS_DIR%\DEBUG_LOBBY_CONNECT_X86.LKS
+echo /link /OUT:%OLD_DIR%\debug\lobby_connect\lobby_connect_x32.exe >> %CDS_DIR%\DEBUG_LOBBY_CONNECT_X86.LKS
+echo /link /IMPLIB:%cd%\lobby_connect_x32.lib >> %CDS_DIR%\DEBUG_LOBBY_CONNECT_X86.LKS
+IF NOT EXIST %OLD_DIR%\CI_BUILD.TAG ( echo /link /PDB:%OLD_DIR%\debug\lobby_connect\lobby_connect_x32.pdb >> %CDS_DIR%\DEBUG_LOBBY_CONNECT_X86.LKS )
+
+cl @%CDS_DIR%\DEBUG.LKS @%CDS_DIR%\PROTOBUF_X86.BLD @%CDS_DIR%\PROTOBUF_X86.LKS @%CDS_DIR%\LOBBY_CONNECT.LKS @%CDS_DIR%\DEBUG_LOBBY_CONNECT_X86.LKS
cd %OLD_DIR%
-copy Readme_lobby_connect.txt debug\lobby_connect\Readme.txt
endlocal
+
+setlocal
+"%PROTOC_X86_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
+call build_env_x64.bat
+cd %OLD_DIR%\build\lobby_connect\debug\x64
+
+cl /c @%CDS_DIR%\DEBUG.BLD @%CDS_DIR%\PROTOBUF_X64.BLD @%CDS_DIR%\LOBBY_CONNECT.BLD
+IF EXIST %CDS_DIR%\DEBUG_LOBBY_CONNECT_X64.LKS ( DEL /F /Q %CDS_DIR%\DEBUG_LOBBY_CONNECT_X64.LKS )
+where "*.obj" > %CDS_DIR%\DEBUG_LOBBY_CONNECT_X64.LKS
+echo /link /OUT:%OLD_DIR%\debug\lobby_connect\lobby_connect_x64.exe >> %CDS_DIR%\DEBUG_LOBBY_CONNECT_X64.LKS
+echo /link /IMPLIB:%cd%\lobby_connect_x64.lib >> %CDS_DIR%\DEBUG_LOBBY_CONNECT_X64.LKS
+IF NOT EXIST %OLD_DIR%\CI_BUILD.TAG ( echo /link /PDB:%OLD_DIR%\debug\lobby_connect\lobby_connect_x64.pdb >> %CDS_DIR%\DEBUG_LOBBY_CONNECT_X64.LKS )
+
+cl @%CDS_DIR%\DEBUG.LKS @%CDS_DIR%\PROTOBUF_X64.BLD @%CDS_DIR%\PROTOBUF_X64.LKS @%CDS_DIR%\LOBBY_CONNECT.LKS @%CDS_DIR%\DEBUG_LOBBY_CONNECT_X64.LKS
+cd %OLD_DIR%
+endlocal
+copy Readme_lobby_connect.txt debug\lobby_connect\Readme.txt
diff --git a/build_win_find_interfaces.bat b/build_win_find_interfaces.bat
index ca77c84..36f834e 100755
--- a/build_win_find_interfaces.bat
+++ b/build_win_find_interfaces.bat
@@ -1,20 +1,39 @@
@echo off
cd /d "%~dp0"
-IF NOT EXIST build ( mkdir build )
-IF NOT EXIST build\release ( mkdir build\release )
-IF NOT EXIST build\release\tools ( mkdir build\release\tools )
-IF NOT EXIST build\release\tools\x86 ( mkdir build\release\tools\x86 )
-IF EXIST build\release\tools\x86\*.* ( DEL /F /S /Q build\release\tools\x86\*.* )
+SET OLD_DIR=%cd%
+
+IF NOT "%1" == "" ( SET JOB_COUNT=%~1 )
+
+IF NOT DEFINED BUILT_ALL_DEPS ( call generate_all_deps.bat )
+
+IF EXIST build\release\tools\x86\*.* ( DEL /F /S /Q build\release\tools\x86\*.* )
+IF EXIST build\release\tools\x64\*.* ( DEL /F /S /Q build\release\tools\x64\*.* )
-IF NOT EXIST release\tools ( mkdir release\tools )
IF EXIST release\tools\*.* ( DEL /F /S /Q release\tools\*.* )
setlocal
call build_env_x86.bat
-SET OLD_DIR=%cd%
-cd build\release\tools\x86
-cl %OLD_DIR%/generate_interfaces_file.cpp /EHsc /MP12 /Ox /link /debug:none /OUT:%OLD_DIR%\release\tools\generate_interfaces_file.exe
+cd %OLD_DIR%\build\release\tools\x86
+cl /c @%CDS_DIR%\RELEASE.BLD @%CDS_DIR%\GENERATE_INTERFACES_FILE.BLD
+IF EXIST %CDS_DIR%\RELEASE_GENERATE_INTERFACES_FILE_X86.LKS ( DEL /F /Q %CDS_DIR%\RELEASE_GENERATE_INTERFACES_FILE_X86.LKS )
+where "generate_interfaces_file.obj" > %CDS_DIR%\RELEASE_GENERATE_INTERFACES_FILE_X86.LKS
+echo /link /OUT:%OLD_DIR%\release\tools\generate_interfaces_file_x32.exe >> %CDS_DIR%\RELEASE_GENERATE_INTERFACES_FILE_X86.LKS
+IF NOT EXIST %OLD_DIR%\CI_BUILD.TAG ( echo /link /PDB:%OLD_DIR%\release\tools\generate_interfaces_file_x32.pdb >> %CDS_DIR%\RELEASE_GENERATE_INTERFACES_FILE_X86.LKS )
+cl @%CDS_DIR%\RELEASE.LKS @%CDS_DIR%\GENERATE_INTERFACES_FILE.LKS @%CDS_DIR%\RELEASE_GENERATE_INTERFACES_FILE_X86.LKS
cd %OLD_DIR%
-copy Readme_generate_interfaces.txt release\tools\Readme_generate_interfaces.txt
endlocal
+
+setlocal
+call build_env_x64.bat
+cd %OLD_DIR%\build\release\tools\x64
+cl /c @%CDS_DIR%\RELEASE.BLD @%CDS_DIR%\GENERATE_INTERFACES_FILE.BLD
+IF EXIST %CDS_DIR%\RELEASE_GENERATE_INTERFACES_FILE_X64.LKS ( DEL /F /Q %CDS_DIR%\RELEASE_GENERATE_INTERFACES_FILE_X64.LKS )
+where "generate_interfaces_file.obj" > %CDS_DIR%\RELEASE_GENERATE_INTERFACES_FILE_X64.LKS
+echo /link /OUT:%OLD_DIR%\release\tools\generate_interfaces_file_x64.exe >> %CDS_DIR%\RELEASE_GENERATE_INTERFACES_FILE_X64.LKS
+IF NOT EXIST %OLD_DIR%\CI_BUILD.TAG ( echo /link /PDB:%OLD_DIR%\release\tools\generate_interfaces_file_x64.pdb >> %CDS_DIR%\RELEASE_GENERATE_INTERFACES_FILE_X64.LKS )
+cl @%CDS_DIR%\RELEASE.LKS @%CDS_DIR%\GENERATE_INTERFACES_FILE.LKS @%CDS_DIR%\RELEASE_GENERATE_INTERFACES_FILE_X64.LKS
+cd %OLD_DIR%
+endlocal
+
+copy Readme_generate_interfaces.txt release\tools\Readme_generate_interfaces.txt
diff --git a/build_win_lobby_connect.bat b/build_win_lobby_connect.bat
index 046f957..09f194b 100755
--- a/build_win_lobby_connect.bat
+++ b/build_win_lobby_connect.bat
@@ -1,23 +1,46 @@
@echo off
cd /d "%~dp0"
-IF NOT EXIST build ( mkdir build )
-IF NOT EXIST build\release ( mkdir build\release )
-IF NOT EXIST build\release\lobby_connect ( mkdir build\release\lobby_connect )
-IF NOT EXIST build\release\lobby_connect\x86 ( mkdir build\release\lobby_connect\x86 )
-IF EXIST build\release\lobby_connect\x86\*.* ( DEL /F /S /Q build\release\lobby_connect\x86\*.* )
+SET OLD_DIR=%cd%
+
+IF NOT "%1" == "" ( SET JOB_COUNT=%~1 )
+
+IF NOT DEFINED BUILT_ALL_DEPS ( call generate_all_deps.bat )
+
+IF EXIST build\release\lobby_connect\x86\*.* ( DEL /F /S /Q build\release\lobby_connect\x86\*.* )
+IF EXIST build\release\lobby_connect\x64\*.* ( DEL /F /S /Q build\release\lobby_connect\x64\*.* )
-IF NOT EXIST release\lobby_connect ( mkdir release\lobby_connect )
IF EXIST release\lobby_connect\*.* ( DEL /F /S /Q release\lobby_connect\*.* )
-call build_set_protobuf_directories.bat
setlocal
"%PROTOC_X86_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
call build_env_x86.bat
-SET OLD_DIR=%cd%
-cd build\release\lobby_connect\x86
-cl %OLD_DIR%/dll/rtlgenrandom.c %OLD_DIR%/dll/rtlgenrandom.def
-cl /DNO_DISK_WRITES /DLOBBY_CONNECT /DEMU_RELEASE_BUILD /DNDEBUG /I%OLD_DIR%/%PROTOBUF_X86_DIRECTORY%\include\ %OLD_DIR%/lobby_connect.cpp %OLD_DIR%/dll/*.cpp %OLD_DIR%/dll/*.cc "%OLD_DIR%/%PROTOBUF_X86_LIBRARY%" Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Comdlg32.lib /EHsc /MP12 /Ox /link /debug:none /OUT:%OLD_DIR%\release\lobby_connect\lobby_connect.exe
+cd %OLD_DIR%\build\lobby_connect\release\x86
+
+cl /c @%CDS_DIR%\RELEASE.BLD @%CDS_DIR%\PROTOBUF_X86.BLD @%CDS_DIR%\LOBBY_CONNECT.BLD
+IF EXIST %CDS_DIR%\RELEASE_LOBBY_CONNECT_X86.LKS ( DEL /F /Q %CDS_DIR%\RELEASE_LOBBY_CONNECT_X86.LKS )
+where "*.obj" > %CDS_DIR%\RELEASE_LOBBY_CONNECT_X86.LKS
+echo /link /OUT:%OLD_DIR%\release\lobby_connect\lobby_connect_x32.exe >> %CDS_DIR%\RELEASE_LOBBY_CONNECT_X86.LKS
+echo /link /IMPLIB:%cd%\lobby_connect_x32.lib >> %CDS_DIR%\RELEASE_LOBBY_CONNECT_X86.LKS
+IF NOT EXIST %OLD_DIR%\CI_BUILD.TAG ( echo /link /PDB:%OLD_DIR%\release\lobby_connect\lobby_connect_x32.pdb >> %CDS_DIR%\RELEASE_LOBBY_CONNECT_X86.LKS )
+
+cl @%CDS_DIR%\RELEASE.LKS @%CDS_DIR%\PROTOBUF_X86.BLD @%CDS_DIR%\PROTOBUF_X86.LKS @%CDS_DIR%\LOBBY_CONNECT.LKS @%CDS_DIR%\RELEASE_LOBBY_CONNECT_X86.LKS
cd %OLD_DIR%
-copy Readme_lobby_connect.txt release\lobby_connect\Readme.txt
endlocal
+
+setlocal
+"%PROTOC_X86_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
+call build_env_x64.bat
+cd %OLD_DIR%\build\lobby_connect\release\x64
+
+cl /c @%CDS_DIR%\RELEASE.BLD @%CDS_DIR%\PROTOBUF_X64.BLD @%CDS_DIR%\LOBBY_CONNECT.BLD
+IF EXIST %CDS_DIR%\RELEASE_LOBBY_CONNECT_X64.LKS ( DEL /F /Q %CDS_DIR%\RELEASE_LOBBY_CONNECT_X64.LKS )
+where "*.obj" > %CDS_DIR%\RELEASE_LOBBY_CONNECT_X64.LKS
+echo /link /OUT:%OLD_DIR%\release\lobby_connect\lobby_connect_x64.exe >> %CDS_DIR%\RELEASE_LOBBY_CONNECT_X64.LKS
+echo /link /IMPLIB:%cd%\lobby_connect_x64.lib >> %CDS_DIR%\RELEASE_LOBBY_CONNECT_X64.LKS
+IF NOT EXIST %OLD_DIR%\CI_BUILD.TAG ( echo /link /PDB:%OLD_DIR%\release\lobby_connect\lobby_connect_x64.pdb >> %CDS_DIR%\RELEASE_LOBBY_CONNECT_X64.LKS )
+
+cl @%CDS_DIR%\RELEASE.LKS @%CDS_DIR%\PROTOBUF_X64.BLD @%CDS_DIR%\PROTOBUF_X64.LKS @%CDS_DIR%\LOBBY_CONNECT.LKS @%CDS_DIR%\RELEASE_LOBBY_CONNECT_X64.LKS
+cd %OLD_DIR%
+endlocal
+copy Readme_lobby_connect.txt release\lobby_connect\Readme.txt
diff --git a/build_win_release.bat b/build_win_release.bat
index a89eae0..31e3854 100755
--- a/build_win_release.bat
+++ b/build_win_release.bat
@@ -1,42 +1,51 @@
@echo off
cd /d "%~dp0"
-IF NOT EXIST build ( mkdir build )
-IF NOT EXIST build\release ( mkdir build\release )
-IF NOT EXIST build\release\x86 ( mkdir build\release\x86 )
-IF NOT EXIST build\release\x64 ( mkdir build\release\x64 )
+SET OLD_DIR=%cd%
+
+IF NOT "%1" == "" ( SET JOB_COUNT=%~1 )
+
+IF NOT DEFINED BUILT_ALL_DEPS ( call generate_all_deps.bat )
+
IF EXIST build\release\x86\*.* ( DEL /F /S /Q build\release\x86\*.* )
IF EXIST build\release\x64\*.* ( DEL /F /S /Q build\release\x64\*.* )
-IF NOT EXIST release ( mkdir release )
IF EXIST release\steam_settings.EXAMPLE ( DEL /F /S /Q release\steam_settings.EXAMPLE )
IF EXIST release\*.dll ( DEL /F /Q release\*.dll )
IF EXIST release\*.txt ( DEL /F /Q release\*.txt )
-call build_set_protobuf_directories.bat
-
-SET OLD_DIR=%cd%
-
setlocal
"%PROTOC_X86_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
call build_env_x86.bat
-cd build\release\x86
-cl %OLD_DIR%/dll/rtlgenrandom.c %OLD_DIR%/dll/rtlgenrandom.def
-cl /LD /DEMU_RELEASE_BUILD /DNDEBUG /I%OLD_DIR%/%PROTOBUF_X86_DIRECTORY%\include\ %OLD_DIR%/dll/*.cpp %OLD_DIR%/dll/*.cc "%OLD_DIR%/%PROTOBUF_X86_LIBRARY%" Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib /EHsc /MP12 /Ox /link /debug:none /OUT:%OLD_DIR%\release\steam_api.dll
+cd %OLD_DIR%\build\release\x86
+
+cl /c @%CDS_DIR%\RELEASE.BLD @%CDS_DIR%\PROTOBUF_X86.BLD @%CDS_DIR%\DLL_MAIN_CPP.BLD
+IF EXIST %CDS_DIR%\RELEASE_BASE_DLL_X86.LKS ( DEL /F /Q %CDS_DIR%\RELEASE_BASE_DLL_X86.LKS )
+where "*.obj" > %CDS_DIR%\RELEASE_BASE_DLL_X86.LKS
+echo /link /OUT:%OLD_DIR%\release\steam_api.dll >> %CDS_DIR%\RELEASE_BASE_DLL_X86.LKS
+IF NOT EXIST %OLD_DIR%\CI_BUILD.TAG ( echo /link /PDB:%OLD_DIR%\release\steam_api.pdb >> %CDS_DIR%\RELEASE_BASE_DLL_X86.LKS )
+
+cl /LD @%CDS_DIR%/RELEASE.LKS @%CDS_DIR%/PROTOBUF_X86.LKS @%CDS_DIR%/DLL_MAIN_CPP.LKS @%CDS_DIR%\RELEASE_BASE_DLL_X86.LKS
cd %OLD_DIR%
endlocal
setlocal
"%PROTOC_X64_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
call build_env_x64.bat
-cd build\release\x64
-cl %OLD_DIR%/dll/rtlgenrandom.c %OLD_DIR%/dll/rtlgenrandom.def
-cl /LD /DEMU_RELEASE_BUILD /DNDEBUG /I%OLD_DIR%/%PROTOBUF_X64_DIRECTORY%\include\ %OLD_DIR%/dll/*.cpp %OLD_DIR%/dll/*.cc "%OLD_DIR%/%PROTOBUF_X64_LIBRARY%" Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib /EHsc /MP12 /Ox /link /debug:none /OUT:%OLD_DIR%\release\steam_api64.dll
+cd %OLD_DIR%\build\release\x64
+
+cl /c @%CDS_DIR%/RELEASE.BLD @%CDS_DIR%/PROTOBUF_X64.BLD @%CDS_DIR%/DLL_MAIN_CPP.BLD
+IF EXIST %CDS_DIR%\RELEASE_BASE_DLL_X64.LKS ( DEL /F /Q %CDS_DIR%\RELEASE_BASE_DLL_X64.LKS )
+where "*.obj" > %CDS_DIR%\RELEASE_BASE_DLL_X64.LKS
+echo /link /OUT:%OLD_DIR%\release\steam_api64.dll >> %CDS_DIR%\RELEASE_BASE_DLL_X64.LKS
+IF NOT EXIST %OLD_DIR%\CI_BUILD.TAG ( echo /link /PDB:%OLD_DIR%\release\steam_api64.pdb >> %CDS_DIR%\RELEASE_BASE_DLL_X64.LKS )
+
+cl /LD @%CDS_DIR%/RELEASE.LKS @%CDS_DIR%/PROTOBUF_X64.LKS @%CDS_DIR%/DLL_MAIN_CPP.LKS @%CDS_DIR%\RELEASE_BASE_DLL_X64.LKS
cd %OLD_DIR%
+
endlocal
copy Readme_release.txt release\Readme.txt
xcopy /s files_example\* release\
-call build_win_release_experimental.bat
call build_win_release_experimental_steamclient.bat
call build_win_lobby_connect.bat
call build_win_find_interfaces.bat
diff --git a/build_win_release_experimental.bat b/build_win_release_experimental.bat
index 0e7d6ad..faa8230 100755
--- a/build_win_release_experimental.bat
+++ b/build_win_release_experimental.bat
@@ -1,37 +1,9 @@
@echo off
cd /d "%~dp0"
-IF NOT EXIST build ( mkdir build )
-IF NOT EXIST build\experimental ( mkdir build\experimental )
-IF NOT EXIST build\experimental\release ( mkdir build\experimental\release )
-IF NOT EXIST build\experimental\release\x86 ( mkdir build\experimental\release\x86 )
-IF NOT EXIST build\experimental\release\x64 ( mkdir build\experimental\release\x64 )
-IF EXIST build\experimental\release\x86\*.* ( DEL /F /S /Q build\experimental\release\x86\*.* )
-IF EXIST build\experimental\release\x64\*.* ( DEL /F /S /Q build\experimental\release\x64\*.* )
-IF NOT EXIST release\experimental ( mkdir release\experimental )
-IF EXIST release\experimental\*.* ( DEL /F /S /Q release\experimental\*.* )
+IF NOT "%1" == "" ( SET JOB_COUNT=%~1 )
-call build_set_protobuf_directories.bat
+SET SKIP_EXPERIMENTAL_STEAMCLIENT_BUILD=1
+SET SKIP_STEAMCLIENT_LOADER=1
-setlocal
-"%PROTOC_X86_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
-call build_env_x86.bat
-SET OLD_DIR=%cd%
-cd "build\experimental\release\x86"
-cl %OLD_DIR%/dll/rtlgenrandom.c %OLD_DIR%/dll/rtlgenrandom.def
-cl /LD /DEMU_RELEASE_BUILD /DEMU_EXPERIMENTAL_BUILD /DCONTROLLER_SUPPORT /DEMU_OVERLAY /DNDEBUG /I%OLD_DIR%/ImGui /I%OLD_DIR%/%PROTOBUF_X86_DIRECTORY%\include\ /I%OLD_DIR%/overlay_experimental %OLD_DIR%/dll/*.cpp %OLD_DIR%/dll/*.cc %OLD_DIR%/detours/*.cpp %OLD_DIR%/controller/gamepad.c %OLD_DIR%/ImGui/*.cpp %OLD_DIR%/ImGui/backends/imgui_impl_dx*.cpp %OLD_DIR%/ImGui/backends/imgui_impl_win32.cpp %OLD_DIR%/ImGui/backends/imgui_impl_vulkan.cpp %OLD_DIR%/ImGui/backends/imgui_impl_opengl3.cpp %OLD_DIR%/ImGui/backends/imgui_win_shader_blobs.cpp %OLD_DIR%/overlay_experimental/*.cpp %OLD_DIR%/overlay_experimental/windows/*.cpp %OLD_DIR%/overlay_experimental/System/*.cpp "%OLD_DIR%/%PROTOBUF_X86_LIBRARY%" opengl32.lib Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Winmm.lib /EHsc /MP12 /Ox /link /debug:none /OUT:%OLD_DIR%\release\experimental\steam_api.dll
-cl /LD /DEMU_RELEASE_BUILD /DEMU_EXPERIMENTAL_BUILD /DNDEBUG %OLD_DIR%/steamclient.cpp /EHsc /MP4 /Ox /link /OUT:%OLD_DIR%\release\experimental\steamclient.dll
-cd %OLD_DIR%
-endlocal
-
-setlocal
-"%PROTOC_X64_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
-call build_env_x64.bat
-SET OLD_DIR=%cd%
-cd "%OLD_DIR%\build\experimental\release\x64"
-cl %OLD_DIR%/dll/rtlgenrandom.c %OLD_DIR%/dll/rtlgenrandom.def
-cl /LD /DEMU_RELEASE_BUILD /DEMU_EXPERIMENTAL_BUILD /DCONTROLLER_SUPPORT /DEMU_OVERLAY /DNDEBUG /I%OLD_DIR%/ImGui /I%OLD_DIR%/%PROTOBUF_X64_DIRECTORY%\include\ /I%OLD_DIR%/overlay_experimental %OLD_DIR%/dll/*.cpp %OLD_DIR%/dll/*.cc %OLD_DIR%/detours/*.cpp %OLD_DIR%/controller/gamepad.c %OLD_DIR%/ImGui/*.cpp %OLD_DIR%/ImGui/backends/imgui_impl_dx*.cpp %OLD_DIR%/ImGui/backends/imgui_impl_win32.cpp %OLD_DIR%/ImGui/backends/imgui_impl_vulkan.cpp %OLD_DIR%/ImGui/backends/imgui_impl_opengl3.cpp %OLD_DIR%/ImGui/backends/imgui_win_shader_blobs.cpp %OLD_DIR%/overlay_experimental/*.cpp %OLD_DIR%/overlay_experimental/windows/*.cpp %OLD_DIR%/overlay_experimental/System/*.cpp "%OLD_DIR%/%PROTOBUF_X64_LIBRARY%" opengl32.lib Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Winmm.lib /EHsc /MP12 /Ox /link /debug:none /OUT:%OLD_DIR%\release\experimental\steam_api64.dll
-cl /LD /DEMU_RELEASE_BUILD /DEMU_EXPERIMENTAL_BUILD /DNDEBUG %OLD_DIR%/steamclient.cpp /EHsc /MP4 /Ox /link /OUT:%OLD_DIR%\release\experimental\steamclient64.dll
-cd %OLD_DIR%
-copy Readme_experimental.txt release\experimental\Readme.txt
-endlocal
+call build_win_release_experimental_steamclient.bat
diff --git a/build_win_release_experimental_steamclient.bat b/build_win_release_experimental_steamclient.bat
index 5ff6d23..800c195 100644
--- a/build_win_release_experimental_steamclient.bat
+++ b/build_win_release_experimental_steamclient.bat
@@ -1,38 +1,141 @@
@echo off
cd /d "%~dp0"
-IF NOT EXIST build ( mkdir build )
-IF NOT EXIST build\experimental ( mkdir build\experimental )
-IF NOT EXIST build\experimental\steamclient ( mkdir build\experimental\steamclient )
-IF NOT EXIST build\experimental\steamclient\release ( mkdir build\experimental\steamclient\release )
-IF NOT EXIST build\experimental\steamclient\release\x86 ( mkdir build\experimental\steamclient\release\x86 )
-IF NOT EXIST build\experimental\steamclient\release\x64 ( mkdir build\experimental\steamclient\release\x64 )
+
+SET OLD_DIR=%cd%
+
+IF NOT "%1" == "" ( SET JOB_COUNT=%~1 )
+
+IF NOT DEFINED BUILT_ALL_DEPS ( call generate_all_deps.bat )
+
IF EXIST build\experimental\steamclient\release\x86\*.* ( DEL /F /S /Q build\experimental\steamclient\release\x86\*.* )
IF EXIST build\experimental\steamclient\release\x64\*.* ( DEL /F /S /Q build\experimental\steamclient\release\x64\*.* )
-IF NOT EXIST release\experimental_steamclient ( mkdir release\experimental_steamclient )
IF EXIST release\experimental_steamclient\*.* ( DEL /F /S /Q release\experimental_steamclient\*.* )
-call build_set_protobuf_directories.bat
-
setlocal
+
+IF DEFINED SKIP_X86 GOTO LK_X64
+
"%PROTOC_X86_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
call build_env_x86.bat
-SET OLD_DIR=%cd%
-cd "build\experimental\steamclient\release\x86"
-cl %OLD_DIR%/dll/rtlgenrandom.c %OLD_DIR%/dll/rtlgenrandom.def
-cl /LD /DEMU_RELEASE_BUILD /DEMU_EXPERIMENTAL_BUILD /DSTEAMCLIENT_DLL /DCONTROLLER_SUPPORT /DEMU_OVERLAY /I%OLD_DIR%/ImGui /DNDEBUG /I%OLD_DIR%/%PROTOBUF_X86_DIRECTORY%\include\ /I%OLD_DIR%/overlay_experimental %OLD_DIR%/dll/*.cpp %OLD_DIR%/dll/*.cc %OLD_DIR%/detours/*.cpp %OLD_DIR%/controller/gamepad.c %OLD_DIR%/ImGui/*.cpp %OLD_DIR%/ImGui/backends/imgui_impl_dx*.cpp %OLD_DIR%/ImGui/backends/imgui_impl_win32.cpp %OLD_DIR%/ImGui/backends/imgui_impl_vulkan.cpp %OLD_DIR%/ImGui/backends/imgui_impl_opengl3.cpp %OLD_DIR%/ImGui/backends/imgui_win_shader_blobs.cpp %OLD_DIR%/overlay_experimental/*.cpp %OLD_DIR%/overlay_experimental/windows/*.cpp %OLD_DIR%/overlay_experimental/System/*.cpp "%OLD_DIR%/%PROTOBUF_X86_LIBRARY%" opengl32.lib Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Winmm.lib /EHsc /MP12 /Ox /link /debug:none /OUT:%OLD_DIR%\release\experimental_steamclient\steamclient.dll
-cl %OLD_DIR%/steamclient_loader/*.cpp advapi32.lib user32.lib /EHsc /MP12 /Ox /link /debug:none /OUT:%OLD_DIR%\release\experimental_steamclient\steamclient_loader_x32.exe
+
+REM Non-STEAMCLIENT_DLL release sc_deps.
+cd "%OLD_DIR%\build\experimental_steamclient\release\x86\sc_deps"
+cl /c @%CDS_DIR%\RELEASE.BLD @%CDS_DIR%\PROTOBUF_X86.BLD @%CDS_DIR%\SC_DEPS.BLD
+IF EXIST %CDS_DIR%\RELEASE_SC_DEPS_X86.LKS ( DEL /F /Q %CDS_DIR%\RELEASE_SC_DEPS_X86.LKS )
+where "*.obj" > %CDS_DIR%\RELEASE_SC_DEPS_X86.LKS
+
+IF DEFINED SKIP_EXPERIMENTAL_BUILD GOTO LK_EXP_STEAMCLIENT_DLL_X86
+
+REM Link Non-STEAMCLIENT_DLL release steam_api.dll.
+cd "%OLD_DIR%\build\experimental\release\x86\"
+IF EXIST %CDS_DIR%\RELEASE_STEAMAPI_NON_X86.LKS ( DEL /F /Q %CDS_DIR%\RELEASE_STEAMAPI_NON_X86.LKS )
+echo /link /OUT:%OLD_DIR%\release\experimental\steam_api.dll > %CDS_DIR%\RELEASE_STEAMAPI_NON_X86.LKS
+IF NOT EXIST %OLD_DIR%\CI_BUILD.TAG ( echo /link /PDB:%OLD_DIR%\release\experimental\steam_api.pdb >> %CDS_DIR%\RELEASE_STEAMAPI_NON_X86.LKS )
+cl /LD @%CDS_DIR%\RELEASE.LKS @%CDS_DIR%\PROTOBUF_X86.LKS @%CDS_DIR%\EXPERIMENTAL.BLD @%CDS_DIR%\EXPERIMENTAL.LKS @%CDS_DIR%\RELEASE_ALL_DEPS_X86.LKS @%CDS_DIR%\RELEASE_SC_DEPS_X86.LKS @%CDS_DIR%\RELEASE_STEAMAPI_NON_X86.LKS
+
+:LK_EXP_STEAMCLIENT_DLL_X86
+
+IF DEFINED SKIP_EXPERIMENTAL_STEAMCLIENT_BUILD GOTO LK_STEAMCLIENT_DLL_X86
+
+REM Link STEAMCLIENT_DLL release steamclient.dll
+cd "%OLD_DIR%\build\experimental_steamclient\release\x86"
+IF EXIST %CDS_DIR%\RELEASE_STEAMCLIENT_X86.LKS ( DEL /F /Q %CDS_DIR%\RELEASE_STEAMCLIENT_X86.LKS )
+echo /link /OUT:%OLD_DIR%\release\experimental_steamclient\steamclient.dll > %CDS_DIR%\RELEASE_STEAMCLIENT_X86.LKS
+IF NOT EXIST %OLD_DIR%\CI_BUILD.TAG ( echo /link /PDB:%OLD_DIR%\release\experimental_steamclient\steamclient.pdb >> %CDS_DIR%\RELEASE_STEAMCLIENT_X86.LKS )
+cl /LD @%CDS_DIR%\RELEASE.LKS @%CDS_DIR%\PROTOBUF_X86.LKS @%CDS_DIR%\EXPERIMENTAL_STEAMCLIENT.LKS @%CDS_DIR%\RELEASE_ALL_DEPS_X86.LKS @%CDS_DIR%\RELEASE_SC_DEPS_X86.LKS @%CDS_DIR%\RELEASE_STEAMCLIENT_X86.LKS
+
+:LK_STEAMCLIENT_DLL_X86
+
+IF DEFINED SKIP_EXPERIMENTAL_BUILD GOTO LK_STEAMCLIENT_LOADER_X86
+
+REM Link Non-STEAMCLIENT_DLL release steamclient.dll.
+cd "%OLD_DIR%\build\experimental\release\x86\"
+IF EXIST %CDS_DIR%\RELEASE_STEAMCLIENT_NON_X86.LKS ( DEL /F /Q %CDS_DIR%\RELEASE_STEAMCLIENT_NON_X86.LKS )
+echo /link /OUT:%OLD_DIR%\release\experimental\steamclient.dll > %CDS_DIR%\RELEASE_STEAMCLIENT_NON_X86.LKS
+IF NOT EXIST %OLD_DIR%\CI_BUILD.TAG ( echo /link /PDB:%OLD_DIR%\release\experimental\steamclient.pdb >> %CDS_DIR%\RELEASE_STEAMCLIENT_NON_X86.LKS )
+cl /LD @%CDS_DIR%\RELEASE.LKS @%CDS_DIR%\STEAMCLIENT.BLD @%CDS_DIR%\RELEASE_STEAMCLIENT_NON_X86.LKS
+
+:LK_STEAMCLIENT_LOADER_X86
+
+IF DEFINED SKIP_STEAMCLIENT_LOADER GOTO LK_X64
+
+REM Build steamclient_loader release x86.
+cd "%OLD_DIR%\build\experimental_steamclient\steamclient_loader\release\x86"
+cl /c @%CDS_DIR%\RELEASE.BLD @%CDS_DIR%\STEAMCLIENT_LOADER.BLD
+IF EXIST %CDS_DIR%\RELEASE_STEAMCLIENT_LOADER_X86.LKS ( DEL /F /Q %CDS_DIR%\RELEASE_STEAMCLIENT_LOADER_X86.LKS )
+where "*.obj" > %CDS_DIR%\RELEASE_STEAMCLIENT_LOADER_X86.LKS
+echo /link /OUT:%OLD_DIR%\release\experimental_steamclient\steamclient_loader_x32.exe >> %CDS_DIR%\RELEASE_STEAMCLIENT_LOADER_X86.LKS
+IF NOT EXIST %OLD_DIR%\CI_BUILD.TAG ( echo /link /PDB:%OLD_DIR%\release\experimental_steamclient\steamclient_loader_x32.pdb >> %CDS_DIR%\RELEASE_STEAMCLIENT_LOADER_X86.LKS )
+cl @%CDS_DIR%\RELEASE.LKS @%CDS_DIR%\STEAMCLIENT_LOADER.LKS @%CDS_DIR%\RELEASE_STEAMCLIENT_LOADER_X86.LKS
cd %OLD_DIR%
-copy steamclient_loader\ColdClientLoader.ini release\experimental_steamclient\
+
+:LK_X64
+
endlocal
+
setlocal
+
+IF DEFINED SKIP_X64 GOTO LK_END
+
"%PROTOC_X64_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
call build_env_x64.bat
-SET OLD_DIR=%cd%
-cd "build\experimental\steamclient\release\x64"
-cl %OLD_DIR%/dll/rtlgenrandom.c %OLD_DIR%/dll/rtlgenrandom.def
-cl /LD /DEMU_RELEASE_BUILD /DEMU_EXPERIMENTAL_BUILD /DSTEAMCLIENT_DLL /DCONTROLLER_SUPPORT /DEMU_OVERLAY /I%OLD_DIR%/ImGui /DNDEBUG /I%OLD_DIR%/%PROTOBUF_X64_DIRECTORY%\include\ /I%OLD_DIR%/overlay_experimental %OLD_DIR%/dll/*.cpp %OLD_DIR%/dll/*.cc %OLD_DIR%/detours/*.cpp %OLD_DIR%/controller/gamepad.c %OLD_DIR%/ImGui/*.cpp %OLD_DIR%/ImGui/backends/imgui_impl_dx*.cpp %OLD_DIR%/ImGui/backends/imgui_impl_win32.cpp %OLD_DIR%/ImGui/backends/imgui_impl_vulkan.cpp %OLD_DIR%/ImGui/backends/imgui_impl_opengl3.cpp %OLD_DIR%/ImGui/backends/imgui_win_shader_blobs.cpp %OLD_DIR%/overlay_experimental/*.cpp %OLD_DIR%/overlay_experimental/windows/*.cpp %OLD_DIR%/overlay_experimental/System/*.cpp "%OLD_DIR%/%PROTOBUF_X64_LIBRARY%" opengl32.lib Iphlpapi.lib Ws2_32.lib rtlgenrandom.lib Shell32.lib Winmm.lib /EHsc /MP12 /Ox /link /debug:none /OUT:%OLD_DIR%\release\experimental_steamclient\steamclient64.dll
-cl %OLD_DIR%/steamclient_loader/*.cpp advapi32.lib user32.lib /EHsc /MP12 /Ox /link /debug:none /OUT:%OLD_DIR%\release\experimental_steamclient\steamclient_loader_x64.exe
+
+REM Non-STEAMCLIENT_DLL release sc_deps.
+cd "%OLD_DIR%\build\experimental_steamclient\release\x64\sc_deps"
+cl /c @%CDS_DIR%\RELEASE.BLD @%CDS_DIR%\PROTOBUF_X64.BLD @%CDS_DIR%\SC_DEPS.BLD
+IF EXIST %CDS_DIR%\RELEASE_SC_DEPS_X64.LKS ( DEL /F /Q %CDS_DIR%\RELEASE_SC_DEPS_X64.LKS )
+where "*.obj" > %CDS_DIR%\RELEASE_SC_DEPS_X64.LKS
+
+IF DEFINED SKIP_EXPERIMENTAL_BUILD GOTO LK_EXP_STEAMCLIENT_DLL_X64
+
+REM Link Non-STEAMCLIENT_DLL release steam_api64.dll.
+cd "%OLD_DIR%\build\experimental\release\x64\"
+IF EXIST %CDS_DIR%\RELEASE_STEAMAPI_NON_X64.LKS ( DEL /F /Q %CDS_DIR%\RELEASE_STEAMAPI_NON_X64.LKS )
+echo /link /OUT:%OLD_DIR%\release\experimental\steam_api64.dll > %CDS_DIR%\RELEASE_STEAMAPI_NON_X64.LKS
+IF NOT EXIST %OLD_DIR%\CI_BUILD.TAG ( echo /link /PDB:%OLD_DIR%\release\experimental\steam_api64.pdb >> %CDS_DIR%\RELEASE_STEAMAPI_NON_X64.LKS )
+cl /LD @%CDS_DIR%\RELEASE.LKS @%CDS_DIR%\PROTOBUF_X64.LKS @%CDS_DIR%\EXPERIMENTAL.BLD @%CDS_DIR%\EXPERIMENTAL.LKS @%CDS_DIR%\RELEASE_ALL_DEPS_X64.LKS @%CDS_DIR%\RELEASE_SC_DEPS_X64.LKS @%CDS_DIR%\RELEASE_STEAMAPI_NON_X64.LKS
+
+:LK_EXP_STEAMCLIENT_DLL_X64
+
+IF DEFINED SKIP_EXPERIMENTAL_STEAMCLIENT_BUILD GOTO LK_STEAMCLIENT_DLL_X64
+
+REM Link STEAMCLIENT_DLL release steamclient64.dll
+cd "%OLD_DIR%\build\experimental_steamclient\release\x64"
+IF EXIST %CDS_DIR%\RELEASE_STEAMCLIENT_X64.LKS ( DEL /F /Q %CDS_DIR%\RELEASE_STEAMCLIENT_X64.LKS )
+echo /link /OUT:%OLD_DIR%\release\experimental_steamclient\steamclient64.dll > %CDS_DIR%\RELEASE_STEAMCLIENT_X64.LKS
+IF NOT EXIST %OLD_DIR%\CI_BUILD.TAG ( echo /link /PDB:%OLD_DIR%\release\experimental_steamclient\steamclient64.pdb >> %CDS_DIR%\RELEASE_STEAMCLIENT_X64.LKS )
+cl /LD @%CDS_DIR%\RELEASE.LKS @%CDS_DIR%\PROTOBUF_X64.LKS @%CDS_DIR%\EXPERIMENTAL_STEAMCLIENT.LKS @%CDS_DIR%\RELEASE_ALL_DEPS_X64.LKS @%CDS_DIR%\RELEASE_SC_DEPS_X64.LKS @%CDS_DIR%\RELEASE_STEAMCLIENT_X64.LKS
+
+:LK_STEAMCLIENT_DLL_X64
+
+IF DEFINED SKIP_EXPERIMENTAL_BUILD GOTO LK_STEAMCLIENT_LOADER_X64
+
+REM Link Non-STEAMCLIENT_DLL release steamclient64.dll.
+cd "%OLD_DIR%\build\experimental\release\x64\"
+IF EXIST %CDS_DIR%\RELEASE_STEAMCLIENT_NON_X64.LKS ( DEL /F /Q %CDS_DIR%\RELEASE_STEAMCLIENT_NON_X64.LKS )
+echo /link /OUT:%OLD_DIR%\release\experimental\steamclient64.dll > %CDS_DIR%\RELEASE_STEAMCLIENT_NON_X64.LKS
+IF NOT EXIST %OLD_DIR%\CI_BUILD.TAG ( echo /link /PDB:%OLD_DIR%\release\experimental\steamclient64.pdb >> %CDS_DIR%\RELEASE_STEAMCLIENT_NON_X64.LKS )
+cl /LD @%CDS_DIR%\RELEASE.LKS @%CDS_DIR%\STEAMCLIENT.BLD @%CDS_DIR%\RELEASE_STEAMCLIENT_NON_X64.LKS
+
+:LK_STEAMCLIENT_LOADER_X64
+
+IF DEFINED SKIP_STEAMCLIENT_LOADER GOTO LK_END
+
+REM Build steamclient_loader release x64.
+cd "%OLD_DIR%\build\experimental_steamclient\steamclient_loader\release\x64"
+cl /c @%CDS_DIR%\RELEASE.BLD @%CDS_DIR%\STEAMCLIENT_LOADER.BLD
+IF EXIST %CDS_DIR%\RELEASE_STEAMCLIENT_LOADER_X64.LKS ( DEL /F /Q %CDS_DIR%\RELEASE_STEAMCLIENT_LOADER_X64.LKS )
+where "*.obj" > %CDS_DIR%\RELEASE_STEAMCLIENT_LOADER_X64.LKS
+echo /link /OUT:%OLD_DIR%\release\experimental_steamclient\steamclient_loader_x64.exe >> %CDS_DIR%\RELEASE_STEAMCLIENT_LOADER_X64.LKS
+IF NOT EXIST %OLD_DIR%\CI_BUILD.TAG ( echo /link /PDB:%OLD_DIR%\release\experimental_steamclient\steamclient_loader_x64.pdb >> %CDS_DIR%\RELEASE_STEAMCLIENT_LOADER_X64.LKS )
+cl @%CDS_DIR%\RELEASE.LKS @%CDS_DIR%\STEAMCLIENT_LOADER.LKS @%CDS_DIR%\RELEASE_STEAMCLIENT_LOADER_X64.LKS
cd %OLD_DIR%
+
+:LK_END
+
+endlocal
+
+copy Readme_experimental.txt release\experimental\Readme.txt
+copy steamclient_loader\ColdClientLoader.ini release\experimental_steamclient\
copy Readme_experimental_steamclient.txt release\experimental_steamclient\Readme.txt
-endlocal
\ No newline at end of file
diff --git a/dll/base.cpp b/dll/base.cpp
index 507e034..10d3622 100644
--- a/dll/base.cpp
+++ b/dll/base.cpp
@@ -19,14 +19,37 @@
#ifdef __WINDOWS__
+HMODULE hadvapi32 = NULL;
+BOOLEAN (NTAPI *real_RtlGenRandom)(PVOID,ULONG) = NULL;
+
static void
randombytes(char * const buf, const size_t size)
{
- while (!RtlGenRandom((PVOID) buf, (ULONG) size)) {
- PRINT_DEBUG("RtlGenRandom ERROR\n");
- Sleep(100);
+ PRINT_DEBUG("%s %p %zu.\n", "mine_RtlGenRandom() called.", buf, size);
+ if (hadvapi32 == NULL) {
+ hadvapi32 = GetModuleHandleW(L"advapi32.dll");
+ if (hadvapi32 == NULL) {
+ PRINT_DEBUG("%s.\n", "GetModuleHandle() failed for advapi32.dll");
+ }
+ PRINT_DEBUG("advapi32.dll handle: 0x%x.\n", hadvapi32);
}
-
+ if (hadvapi32 != NULL &&
+ real_RtlGenRandom == NULL) {
+ real_RtlGenRandom = (BOOLEAN(NTAPI *)(PVOID,ULONG))GetProcAddress(hadvapi32, "SystemFunction036");
+ if (real_RtlGenRandom == NULL) {
+ PRINT_DEBUG("%s.\n", "GetProcAddress() failed for RtlGenRandom()");
+ }
+ PRINT_DEBUG("real_RtlGenRandom address: 0x%p.\n", real_RtlGenRandom);
+ }
+ if (real_RtlGenRandom != NULL) {
+ PRINT_DEBUG("%s.\n", "Calling real_RtlGenRandom");
+ while (!real_RtlGenRandom((PVOID) buf, (ULONG) size)) {
+ PRINT_DEBUG("RtlGenRandom ERROR\n");
+ Sleep(100);
+ }
+ PRINT_DEBUG("%s.\n", "real_RtlGenRandom returned");
+ }
+ return;
}
std::string get_env_variable(std::string name)
diff --git a/dll/rtlgenrandom.c b/dll/rtlgenrandom.c
deleted file mode 100644
index e160da4..0000000
--- a/dll/rtlgenrandom.c
+++ /dev/null
@@ -1,4 +0,0 @@
-#include
-#define RtlGenRandom SystemFunction036
-#define DLLEXPORT __declspec(dllexport)
-DLLEXPORT BOOLEAN WINAPI RtlGenRandom(PVOID in, ULONG len) {}
\ No newline at end of file
diff --git a/dll/rtlgenrandom.def b/dll/rtlgenrandom.def
deleted file mode 100644
index 3f23d20..0000000
--- a/dll/rtlgenrandom.def
+++ /dev/null
@@ -1,3 +0,0 @@
-LIBRARY advapi32.dll
-EXPORTS
-SystemFunction036
\ No newline at end of file
diff --git a/dll/settings_parser.cpp b/dll/settings_parser.cpp
index ef34316..af56f73 100644
--- a/dll/settings_parser.cpp
+++ b/dll/settings_parser.cpp
@@ -217,9 +217,39 @@ uint32 create_localstorage_settings(Settings **settings_client_out, Settings **s
load_custom_broadcasts(Local_Storage::get_game_settings_path() + "custom_master_server.txt", custom_master_server);
// Acount name
- char name[32] = {};
+ char name[32] = { '\0' };
if (local_storage->get_data_settings("account_name.txt", name, sizeof(name) - 1) <= 0) {
- strcpy(name, DEFAULT_NAME);
+ PRINT_DEBUG("%s.\n", "Attempting to set steam user name from system user name");
+#if defined(STEAM_WIN32)
+ DWORD username_dword = 32;
+ wchar_t username[32] = { '\0' };
+ if (GetUserNameW((wchar_t*)&username, &username_dword) == TRUE) {
+ std::wstring username_wstr(username);
+ std::string username_str = utf8_encode(username_wstr);
+ size_t username_len = username_str.length();
+ if (username_len > 0 &&
+ username_len < 31) {
+ memcpy(&name, username_str.c_str(), username_len);
+ name[31] = '\0';
+ }
+ }
+#else
+ char * env_username = getenv("USER");
+ if (env_username != NULL) {
+ size_t username_len = strlen(env_username);
+ if (username_len > 0 &&
+ username_len < 31) {
+ memcpy(&name, env_username, username_len);
+ name[31] = '\0';
+ }
+ }
+#endif
+ char empty_name[32] = { '\0' };
+ if (memcmp(name, empty_name, 32) == 0) {
+ PRINT_DEBUG("%s %s.\n", "Setting steam user name to", DEFAULT_NAME);
+ strcpy(name, DEFAULT_NAME);
+ }
+ PRINT_DEBUG("Username: %s.\n", name);
local_storage->store_data_settings("account_name.txt", name, strlen(name));
}
diff --git a/generate_all_deps.bat b/generate_all_deps.bat
new file mode 100644
index 0000000..974ec06
--- /dev/null
+++ b/generate_all_deps.bat
@@ -0,0 +1,57 @@
+@echo off
+cd /d "%~dp0"
+
+call generate_build_win.bat
+
+IF EXIST build\all_deps\debug\x86\*.* ( DEL /F /S /Q build\all_deps\debug\x86\*.* )
+IF EXIST build\all_deps\debug\x64\*.* ( DEL /F /S /Q build\all_deps\debug\x64\*.* )
+IF EXIST build\all_deps\release\x86\*.* ( DEL /F /S /Q build\all_deps\release\x86\*.* )
+IF EXIST build\all_deps\release\x64\*.* ( DEL /F /S /Q build\all_deps\release\x64\*.* )
+
+call build_set_protobuf_directories.bat
+
+setlocal
+"%PROTOC_X86_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
+call build_env_x86.bat
+SET OLD_DIR=%cd%
+cd "build\all_deps\debug\x86"
+cl /c @%CDS_DIR%/DEBUG.BLD @%CDS_DIR%/PROTOBUF_X86.BLD @%CDS_DIR%\ALL_DEPS.BLD
+IF EXIST %CDS_DIR%\DEBUG_ALL_DEPS_X86.LKS ( DEL /F /Q %CDS_DIR%\DEBUG_ALL_DEPS_X86.LKS )
+where "*.obj" > %CDS_DIR%\DEBUG_ALL_DEPS_X86.LKS
+cd %OLD_DIR%
+endlocal
+
+setlocal
+"%PROTOC_X64_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
+call build_env_x64.bat
+SET OLD_DIR=%cd%
+cd "build\all_deps\debug\x64"
+cl /c @%CDS_DIR%/DEBUG.BLD @%CDS_DIR%/PROTOBUF_X64.BLD @%CDS_DIR%\ALL_DEPS.BLD
+IF EXIST %CDS_DIR%\DEBUG_ALL_DEPS_X64.LKS ( DEL /F /Q %CDS_DIR%\DEBUG_ALL_DEPS_X64.LKS )
+where "*.obj" > %CDS_DIR%\DEBUG_ALL_DEPS_X64.LKS
+cd %OLD_DIR%
+endlocal
+
+setlocal
+"%PROTOC_X86_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
+call build_env_x86.bat
+SET OLD_DIR=%cd%
+cd "build\all_deps\release\x86"
+cl /c @%CDS_DIR%/RELEASE.BLD @%CDS_DIR%/PROTOBUF_X86.BLD @%CDS_DIR%\ALL_DEPS.BLD
+IF EXIST %CDS_DIR%\RELEASE_ALL_DEPS_X86.LKS ( DEL /F /Q %CDS_DIR%\RELEASE_ALL_DEPS_X86.LKS )
+where "*.obj" > %CDS_DIR%\RELEASE_ALL_DEPS_X86.LKS
+cd %OLD_DIR%
+endlocal
+
+setlocal
+"%PROTOC_X64_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
+call build_env_x64.bat
+SET OLD_DIR=%cd%
+cd "build\all_deps\release\x64"
+cl /c @%CDS_DIR%/RELEASE.BLD @%CDS_DIR%/PROTOBUF_X64.BLD @%CDS_DIR%\ALL_DEPS.BLD
+IF EXIST %CDS_DIR%\RELEASE_ALL_DEPS_X64.LKS ( DEL /F /Q %CDS_DIR%\RELEASE_ALL_DEPS_X64.LKS )
+where "*.obj" > %CDS_DIR%\RELEASE_ALL_DEPS_X64.LKS
+cd %OLD_DIR%
+endlocal
+
+SET BUILT_ALL_DEPS=1
diff --git a/generate_build_win.bat b/generate_build_win.bat
new file mode 100644
index 0000000..0372b1a
--- /dev/null
+++ b/generate_build_win.bat
@@ -0,0 +1,406 @@
+@echo off
+REM Should be called from the root of the repo.
+
+REM Make build and output dirs.
+IF NOT EXIST build ( mkdir build )
+IF NOT EXIST build\cmds ( mkdir build\cmds )
+IF NOT EXIST build\debug ( mkdir build\debug )
+IF NOT EXIST build\release ( mkdir build\release )
+IF NOT EXIST build\all_deps ( mkdir build\all_deps )
+IF NOT EXIST build\all_deps\debug ( mkdir build\all_deps\debug )
+IF NOT EXIST build\all_deps\release ( mkdir build\all_deps\release )
+IF NOT EXIST build\experimental ( mkdir build\experimental )
+IF NOT EXIST build\experimental\debug ( mkdir build\experimental\debug )
+IF NOT EXIST build\experimental\release ( mkdir build\experimental\release )
+IF NOT EXIST build\experimental_steamclient ( mkdir build\experimental_steamclient )
+IF NOT EXIST build\experimental_steamclient\debug ( mkdir build\experimental_steamclient\debug )
+IF NOT EXIST build\experimental_steamclient\release ( mkdir build\experimental_steamclient\release )
+IF NOT EXIST build\experimental_steamclient\steamclient_loader ( mkdir build\experimental_steamclient\steamclient_loader )
+IF NOT EXIST build\experimental_steamclient\steamclient_loader\debug ( mkdir build\experimental_steamclient\steamclient_loader\debug )
+IF NOT EXIST build\experimental_steamclient\steamclient_loader\release ( mkdir build\experimental_steamclient\steamclient_loader\release )
+IF NOT EXIST build\lobby_connect\debug ( mkdir build\lobby_connect\debug )
+IF NOT EXIST build\lobby_connect\release ( mkdir build\lobby_connect\release )
+IF NOT EXIST build\release\tools ( mkdir build\release\tools )
+IF NOT EXIST build\release\tools\debug ( mkdir build\release\tools\debug )
+IF NOT EXIST build\release\tools\release ( mkdir build\release\tools\release )
+
+IF NOT EXIST build\debug\x86 ( mkdir build\debug\x86 )
+IF NOT EXIST build\debug\x64 ( mkdir build\debug\x64 )
+IF NOT EXIST build\release\x86 ( mkdir build\release\x86 )
+IF NOT EXIST build\release\x64 ( mkdir build\release\x64 )
+
+IF NOT EXIST build\all_deps\debug\x86 ( mkdir build\all_deps\debug\x86 )
+IF NOT EXIST build\all_deps\debug\x64 ( mkdir build\all_deps\debug\x64 )
+IF NOT EXIST build\all_deps\release\x86 ( mkdir build\all_deps\release\x86 )
+IF NOT EXIST build\all_deps\release\x64 ( mkdir build\all_deps\release\x64 )
+
+IF NOT EXIST build\experimental\debug\x86 ( mkdir build\experimental\debug\x86 )
+IF NOT EXIST build\experimental\debug\x64 ( mkdir build\experimental\debug\x64 )
+IF NOT EXIST build\experimental\release\x86 ( mkdir build\experimental\release\x86 )
+IF NOT EXIST build\experimental\release\x64 ( mkdir build\experimental\release\x64 )
+
+IF NOT EXIST build\experimental_steamclient\debug\x86 ( mkdir build\experimental_steamclient\debug\x86 )
+IF NOT EXIST build\experimental_steamclient\debug\x64 ( mkdir build\experimental_steamclient\debug\x64 )
+IF NOT EXIST build\experimental_steamclient\release\x86 ( mkdir build\experimental_steamclient\release\x86 )
+IF NOT EXIST build\experimental_steamclient\release\x64 ( mkdir build\experimental_steamclient\release\x64 )
+IF NOT EXIST build\experimental_steamclient\debug\x86\deps ( mkdir build\experimental_steamclient\debug\x86\deps )
+IF NOT EXIST build\experimental_steamclient\debug\x64\deps ( mkdir build\experimental_steamclient\debug\x64\deps )
+IF NOT EXIST build\experimental_steamclient\release\x86\deps ( mkdir build\experimental_steamclient\release\x86\deps )
+IF NOT EXIST build\experimental_steamclient\release\x64\deps ( mkdir build\experimental_steamclient\release\x64\deps )
+IF NOT EXIST build\experimental_steamclient\debug\x86\sc_deps ( mkdir build\experimental_steamclient\debug\x86\sc_deps )
+IF NOT EXIST build\experimental_steamclient\debug\x64\sc_deps ( mkdir build\experimental_steamclient\debug\x64\sc_deps )
+IF NOT EXIST build\experimental_steamclient\release\x86\sc_deps ( mkdir build\experimental_steamclient\release\x86\sc_deps )
+IF NOT EXIST build\experimental_steamclient\release\x64\sc_deps ( mkdir build\experimental_steamclient\release\x64\sc_deps )
+
+IF NOT EXIST build\experimental_steamclient\steamclient_loader\debug\x86 ( mkdir build\experimental_steamclient\steamclient_loader\debug\x86 )
+IF NOT EXIST build\experimental_steamclient\steamclient_loader\debug\x64 ( mkdir build\experimental_steamclient\steamclient_loader\debug\x64 )
+IF NOT EXIST build\experimental_steamclient\steamclient_loader\release\x86 ( mkdir build\experimental_steamclient\steamclient_loader\release\x86 )
+IF NOT EXIST build\experimental_steamclient\steamclient_loader\release\x64 ( mkdir build\experimental_steamclient\steamclient_loader\release\x64 )
+
+IF NOT EXIST build\lobby_connect\debug\x86 ( mkdir build\lobby_connect\debug\x86 )
+IF NOT EXIST build\lobby_connect\debug\x64 ( mkdir build\lobby_connect\debug\x64 )
+IF NOT EXIST build\lobby_connect\release\x86 ( mkdir build\lobby_connect\release\x86 )
+IF NOT EXIST build\lobby_connect\release\x64 ( mkdir build\lobby_connect\release\x64 )
+IF NOT EXIST build\release\tools\debug\x86 ( mkdir build\release\tools\debug\x86 )
+IF NOT EXIST build\release\tools\debug\x64 ( mkdir build\release\tools\debug\x64 )
+IF NOT EXIST build\release\tools\release\x86 ( mkdir build\release\tools\release\x86 )
+IF NOT EXIST build\release\tools\release\x64 ( mkdir build\release\tools\release\x64 )
+
+IF NOT EXIST debug ( mkdir debug )
+IF NOT EXIST debug\experimental ( mkdir debug\experimental )
+IF NOT EXIST debug\experimental_steamclient ( mkdir debug\experimental_steamclient )
+IF NOT EXIST debug\lobby_connect ( mkdir debug\lobby_connect )
+IF NOT EXIST debug\tools ( mkdir debug\tools )
+
+IF NOT EXIST release ( mkdir release )
+IF NOT EXIST release\experimental ( mkdir release\experimental )
+IF NOT EXIST release\experimental_steamclient ( mkdir release\experimental_steamclient )
+IF NOT EXIST release\lobby_connect ( mkdir release\lobby_connect )
+IF NOT EXIST release\tools ( mkdir release\tools )
+
+SET CDS_DIR=%cd%\build\cmds
+
+REM
+REM Arguments.
+REM
+
+REM normal_args.
+IF EXIST %CDS_DIR%\NORMAL_ARGS.ARG ( DEL /F /S /Q %CDS_DIR%\NORMAL_ARGS.ARG )
+echo /EHsc > %CDS_DIR%\NORMAL_ARGS.ARG
+echo /Ox >> %CDS_DIR%\NORMAL_ARGS.ARG
+
+REM JOB ARGS.
+IF "%JOB_COUNT%" == "" ( echo /MP1 >> %CDS_DIR%\NORMAL_ARGS.ARG )
+IF NOT "%JOB_COUNT%" == "" ( echo /MP%JOB_COUNT% >> %CDS_DIR%\NORMAL_ARGS.ARG )
+
+REM Debug args.
+IF EXIST %CDS_DIR%\DEBUG.BLD ( DEL /F /S /Q %CDS_DIR%\DEBUG.BLD )
+IF EXIST %CDS_DIR%\DEBUG.LKS ( DEL /F /S /Q %CDS_DIR%\DEBUG.LKS )
+
+REM Create empty file. (No BUILD time args currently.)
+type NUL >> %CDS_DIR%\DEBUG.BLD
+
+REM DISABLE the PDB builds if we are running on the CI. (It can't build them currently.)
+IF EXIST %OLD_DIR%\CI_BUILD.TAG ( echo /link /DEBUG:NONE > %CDS_DIR%\DEBUG.LKS )
+IF NOT EXIST %OLD_DIR%\CI_BUILD.TAG ( echo /link /DEBUG:FULL /OPT:REF /OPT:ICF > %CDS_DIR%\DEBUG.LKS )
+
+REM Release args.
+IF EXIST %CDS_DIR%\RELEASE.ARG ( DEL /F /S /Q %CDS_DIR%\RELEASE.ARG )
+IF EXIST %CDS_DIR%\RELEASE.LKS ( DEL /F /S /Q %CDS_DIR%\RELEASE.LKS )
+REM Release mode Flags.
+echo /DEMU_RELEASE_BUILD > %CDS_DIR%\RELEASE.ARG
+echo /DNDEBUG >> %CDS_DIR%\RELEASE.ARG
+copy %CDS_DIR%\RELEASE.ARG %CDS_DIR%\RELEASE.BLD
+type %CDS_DIR%\RELEASE.ARG > %CDS_DIR%\RELEASE.LKS
+
+REM DISABLE the PDB builds if we are running on the CI. (It can't build them currently.)
+IF EXIST %OLD_DIR%\CI_BUILD.TAG ( echo /link /DEBUG:NONE >> %CDS_DIR%\RELEASE.LKS )
+IF NOT EXIST %OLD_DIR%\CI_BUILD.TAG ( echo /link /DEBUG:FULL /OPT:REF /OPT:ICF >> %CDS_DIR%\RELEASE.LKS )
+
+REM BASE DLL Flags.
+IF EXIST %CDS_DIR%\DLL_MAIN_CPP.ARG ( DEL /F /S /Q %CDS_DIR%\DLL_MAIN_CPP.ARG )
+
+REM EXPERIMENTAL Flags.
+IF EXIST %CDS_DIR%\EXPERIMENTAL.ARG ( DEL /F /S /Q %CDS_DIR%\EXPERIMENTAL.ARG )
+echo /DEMU_EXPERIMENTAL_BUILD > %CDS_DIR%\EXPERIMENTAL.ARG
+echo /DCONTROLLER_SUPPORT >> %CDS_DIR%\EXPERIMENTAL.ARG
+echo /DEMU_OVERLAY >> %CDS_DIR%\EXPERIMENTAL.ARG
+
+REM EXPERIMENTAL_STEAMCLIENT Flags.
+IF EXIST %CDS_DIR%\EXPERIMENTAL_STEAMCLIENT.ARG ( DEL /F /S /Q %CDS_DIR%\EXPERIMENTAL_STEAMCLIENT.ARG )
+echo /DSTEAMCLIENT_DLL > %CDS_DIR%\EXPERIMENTAL_STEAMCLIENT.ARG
+
+REM lobby_connect Flags.
+IF EXIST %CDS_DIR%\LOBBY_CONNECT.ARG ( DEL /F /S /Q %CDS_DIR%\LOBBY_CONNECT.ARG )
+echo /DNO_DISK_WRITES > %CDS_DIR%\LOBBY_CONNECT.ARG
+echo /DLOBBY_CONNECT >> %CDS_DIR%\LOBBY_CONNECT.ARG
+
+REM
+REM Includes.
+REM
+
+REM protobuf.
+call build_set_protobuf_directories.bat
+IF EXIST %CDS_DIR%\PROTOBUF_X86.ICD ( DEL /F /S /Q %CDS_DIR%\PROTOBUF_X86.ICD )
+IF EXIST %CDS_DIR%\PROTOBUF_X64.ICD ( DEL /F /S /Q %CDS_DIR%\PROTOBUF_X64.ICD )
+setlocal
+SET TEST_A=%cd%
+cd %PROTOBUF_X86_DIRECTORY%
+SET TEST_B=%cd%\include
+cd %TEST_A%
+echo /I%TEST_B% > %CDS_DIR%\PROTOBUF_X86.ICD
+endlocal
+setlocal
+SET TEST_A=%cd%
+cd %PROTOBUF_X64_DIRECTORY%
+SET TEST_B=%cd%\include
+cd %TEST_A%
+echo /I%TEST_B% > %CDS_DIR%\PROTOBUF_X64.ICD
+endlocal
+
+REM OVERLAY_EXPERIMENTAL.
+IF EXIST %CDS_DIR%\OVERLAY_EXPERIMENTAL.ICD ( DEL /F /S /Q %CDS_DIR%\OVERLAY_EXPERIMENTAL.ICD )
+echo /I%cd%\overlay_experimental > %CDS_DIR%\OVERLAY_EXPERIMENTAL.ICD
+
+REM IMGUI.
+IF EXIST %CDS_DIR%\IMGUI.ICD ( DEL /F /S /Q %CDS_DIR%\IMGUI.ICD )
+echo /I%cd%\ImGui > %CDS_DIR%\IMGUI.ICD
+
+REM
+REM Link Libraries.
+REM
+
+REM protobuf.
+IF EXIST %CDS_DIR%\PROTOBUF_X86.OS ( DEL /F /S /Q %CDS_DIR%\PROTOBUF_X86.OS )
+IF EXIST %CDS_DIR%\PROTOBUF_X64.OS ( DEL /F /S /Q %CDS_DIR%\PROTOBUF_X64.OS )
+dir /b /s %PROTOBUF_X86_LIBRARY% > %CDS_DIR%\PROTOBUF_X86.OS
+dir /b /s %PROTOBUF_X64_LIBRARY% > %CDS_DIR%\PROTOBUF_X64.OS
+
+REM BASE DLL.
+IF EXIST %CDS_DIR%\DLL_MAIN_CPP.OS ( DEL /F /S /Q %CDS_DIR%\DLL_MAIN_CPP.OS )
+echo Iphlpapi.lib > %CDS_DIR%\DLL_MAIN_CPP.OS
+echo Ws2_32.lib >> %CDS_DIR%\DLL_MAIN_CPP.OS
+echo Shell32.lib >> %CDS_DIR%\DLL_MAIN_CPP.OS
+echo advapi32.lib >> %CDS_DIR%\DLL_MAIN_CPP.OS
+
+REM EXPERIMENTAL.
+IF EXIST %CDS_DIR%\EXPERIMENTAL.OS ( DEL /F /S /Q %CDS_DIR%\EXPERIMENTAL.OS )
+echo dbghelp.lib >> %CDS_DIR%\EXPERIMENTAL.OS
+echo Faultrep.lib >> %CDS_DIR%\EXPERIMENTAL.OS
+echo opengl32.lib >> %CDS_DIR%\EXPERIMENTAL.OS
+echo Winmm.lib >> %CDS_DIR%\EXPERIMENTAL.OS
+
+REM steamclient_loader.
+IF EXIST %CDS_DIR%\STEAMCLIENT_LOADER.OS ( DEL /F /S /Q %CDS_DIR%\STEAMCLIENT_LOADER.OS )
+echo advapi32.lib > %CDS_DIR%\STEAMCLIENT_LOADER.OS
+echo user32.lib >> %CDS_DIR%\STEAMCLIENT_LOADER.OS
+
+REM lobby_connect.
+IF EXIST %CDS_DIR%\LOBBY_CONNECT.OS ( DEL /F /S /Q %CDS_DIR%\LOBBY_CONNECT.OS )
+echo Comdlg32.lib > %CDS_DIR%\LOBBY_CONNECT.OS
+
+REM
+REM Files.
+REM
+
+REM Protobuf.
+REM Needs to be compiled here (really just needs to exist), as we include it below.
+"%PROTOC_X86_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\net.proto
+
+REM OVERLAY_EXPERIMENTAL.
+IF EXIST %CDS_DIR%\OVERLAY_EXPERIMENTAL.FLS ( DEL /F /S /Q %CDS_DIR%\OVERLAY_EXPERIMENTAL.FLS )
+IF EXIST %CDS_DIR%\OVERLAY_EXPERIMENTAL_SYSTEM.FLS ( DEL /F /S /Q %CDS_DIR%\OVERLAY_EXPERIMENTAL_SYSTEM.FLS )
+where "%cd%\overlay_experimental\:*.cpp" > %CDS_DIR%\OVERLAY_EXPERIMENTAL.FLS
+where "%cd%\overlay_experimental\windows\:*.cpp" >> %CDS_DIR%\OVERLAY_EXPERIMENTAL.FLS
+where "%cd%\overlay_experimental\System\:*.cpp" >> %CDS_DIR%\OVERLAY_EXPERIMENTAL_SYSTEM.FLS
+
+REM IMGUI.
+IF EXIST %CDS_DIR%\IMGUI.FLS ( DEL /F /S /Q %CDS_DIR%\IMGUI.FLS )
+where "%cd%\ImGui\:*.cpp" > %CDS_DIR%\IMGUI.FLS
+where "%cd%\ImGui\backends\:imgui_impl_dx*.cpp" >> %CDS_DIR%\IMGUI.FLS
+where "%cd%\ImGui\backends\:imgui_impl_win32.cpp" >> %CDS_DIR%\IMGUI.FLS
+where "%cd%\ImGui\backends\:imgui_impl_vulkan.cpp" >> %CDS_DIR%\IMGUI.FLS
+where "%cd%\ImGui\backends\:imgui_impl_opengl3.cpp" >> %CDS_DIR%\IMGUI.FLS
+where "%cd%\ImGui\backends\:imgui_win_shader_blobs.cpp" >> %CDS_DIR%\IMGUI.FLS
+
+REM DETOURS.
+IF EXIST %CDS_DIR%\DETOURS.FLS ( DEL /F /S /Q %CDS_DIR%\DETOURS.FLS )
+where "%cd%\detours\:*.cpp" > %CDS_DIR%\DETOURS.FLS
+
+REM CONTROLLER.
+IF EXIST %CDS_DIR%\CONTROLLER.FLS ( DEL /F /S /Q CONTROLLER.FLS )
+where "%cd%\controller\:gamepad.c" > %CDS_DIR%\CONTROLLER.FLS
+
+REM sc_different_deps.
+IF EXIST %CDS_DIR%\SC_DIFFERENT_DEPS.FLS ( DEL /F /S /Q %CDS_DIR%\SC_DIFFERENT_DEPS.FLS )
+where "%cd%\dll\:flat.cpp" > %CDS_DIR%\SC_DIFFERENT_DEPS.FLS
+where "%cd%\dll\:dll.cpp" >> %CDS_DIR%\SC_DIFFERENT_DEPS.FLS
+
+REM BASE DLL.
+IF EXIST %CDS_DIR%\DLL_MAIN_CPP.FLS ( DEL /F /S /Q %CDS_DIR%\DLL_MAIN_CPP.FLS )
+move %cd%\dll\flat.cpp %cd%\dll\flat.cpp.tmp
+move %cd%\dll\dll.cpp %cd%\dll\dll.cpp.tmp
+where "%cd%\dll\:*.cpp" > %CDS_DIR%\DLL_MAIN_CPP.FLS
+move %cd%\dll\flat.cpp.tmp %cd%\dll\flat.cpp
+move %cd%\dll\dll.cpp.tmp %cd%\dll\dll.cpp
+where "%cd%\dll\:*.cc" >> %CDS_DIR%\DLL_MAIN_CPP.FLS
+
+REM SteamClient.
+IF EXIST %CDS_DIR%\STEAMCLIENT.FLS ( DEL /F /S /Q %CDS_DIR%\STEAMCLIENT.FLS )
+where "%cd%\:steamclient.cpp" > %CDS_DIR%\STEAMCLIENT.FLS
+
+REM steamclient_loader.
+IF EXIST %CDS_DIR%\STEAMCLIENT_LOADER.FLS ( DEL /F /S /Q %CDS_DIR%\STEAMCLIENT_LOADER.FLS )
+where "%cd%\steamclient_loader\:*.cpp" > %CDS_DIR%\STEAMCLIENT_LOADER.FLS
+
+REM lobby_connect.
+IF EXIST %CDS_DIR%\LOBBY_CONNECT.FLS ( DEL /F /S /Q %CDS_DIR%\LOBBY_CONNECT.FLS )
+where "%cd%\:lobby_connect.cpp" > %CDS_DIR%\LOBBY_CONNECT.FLS
+
+REM generate_interfaces_file.
+IF EXIST %CDS_DIR%\GENERATE_INTERFACES_FILE.FLS ( DEL /F /S /Q %CDS_DIR%\GENERATE_INTERFACES_FILE.FLS )
+where "%cd%\:generate_interfaces_file.cpp" > %CDS_DIR%\GENERATE_INTERFACES_FILE.FLS
+
+REM
+REM Build and link cmd script files.
+REM
+
+REM protobuf.
+IF EXIST %CDS_DIR%\PROTOBUF_X86.BLD ( DEL /F /S /Q %CDS_DIR%\PROTOBUF_X86.BLD )
+IF EXIST %CDS_DIR%\PROTOBUF_X86.LKS ( DEL /F /S /Q %CDS_DIR%\PROTOBUF_X86.LKS )
+type %CDS_DIR%\PROTOBUF_X86.ICD > %CDS_DIR%\PROTOBUF_X86.BLD
+type %CDS_DIR%\PROTOBUF_X86.BLD > %CDS_DIR%\PROTOBUF_X86.LKS
+type %CDS_DIR%\PROTOBUF_X86.OS >> %CDS_DIR%\PROTOBUF_X86.LKS
+
+IF EXIST %CDS_DIR%\PROTOBUF_X64.BLD ( DEL /F /S /Q %CDS_DIR%\PROTOBUF_X64.BLD )
+IF EXIST %CDS_DIR%\PROTOBUF_X64.LKS ( DEL /F /S /Q %CDS_DIR%\PROTOBUF_X64.LKS )
+type %CDS_DIR%\PROTOBUF_X64.ICD > %CDS_DIR%\PROTOBUF_X64.BLD
+type %CDS_DIR%\PROTOBUF_X64.BLD > %CDS_DIR%\PROTOBUF_X64.LKS
+type %CDS_DIR%\PROTOBUF_X64.OS >> %CDS_DIR%\PROTOBUF_X64.LKS
+
+REM SC_DEPS
+IF EXIST %CDS_DIR%\SC_DEPS.BLD ( DEL /F /S /Q %CDS_DIR%\SC_DEPS.BLD )
+type %CDS_DIR%\NORMAL_ARGS.ARG > %CDS_DIR%\SC_DEPS.BLD
+type %CDS_DIR%\EXPERIMENTAL.ARG >> %CDS_DIR%\SC_DEPS.BLD
+type %CDS_DIR%\OVERLAY_EXPERIMENTAL.ICD >> %CDS_DIR%\SC_DEPS.BLD
+type %CDS_DIR%\IMGUI.ICD >> %CDS_DIR%\SC_DEPS.BLD
+type %CDS_DIR%\DLL_MAIN_CPP.FLS >> %CDS_DIR%\SC_DEPS.BLD
+type %CDS_DIR%\OVERLAY_EXPERIMENTAL.FLS >> %CDS_DIR%\SC_DEPS.BLD
+
+REM DEPS
+IF EXIST %CDS_DIR%\DEPS.BLD ( DEL /F /S /Q %CDS_DIR%\DEPS.BLD )
+type %CDS_DIR%\DETOURS.FLS >> %CDS_DIR%\DEPS.BLD
+type %CDS_DIR%\CONTROLLER.FLS >> %CDS_DIR%\DEPS.BLD
+type %CDS_DIR%\IMGUI.FLS >> %CDS_DIR%\DEPS.BLD
+type %CDS_DIR%\OVERLAY_EXPERIMENTAL_SYSTEM.FLS >> %CDS_DIR%\DEPS.BLD
+
+REM all_deps.
+IF EXIST %CDS_DIR%\ALL_DEPS.BLD ( DEL /F /S /Q %CDS_DIR%\ALL_DEPS.BLD )
+type %CDS_DIR%\NORMAL_ARGS.ARG > %CDS_DIR%\ALL_DEPS.BLD
+type %CDS_DIR%\OVERLAY_EXPERIMENTAL.ICD >> %CDS_DIR%\ALL_DEPS.BLD
+type %CDS_DIR%\IMGUI.ICD >> %CDS_DIR%\ALL_DEPS.BLD
+type %CDS_DIR%\DETOURS.FLS >> %CDS_DIR%\ALL_DEPS.BLD
+type %CDS_DIR%\CONTROLLER.FLS >> %CDS_DIR%\ALL_DEPS.BLD
+type %CDS_DIR%\IMGUI.FLS >> %CDS_DIR%\ALL_DEPS.BLD
+type %CDS_DIR%\OVERLAY_EXPERIMENTAL_SYSTEM.FLS >> %CDS_DIR%\ALL_DEPS.BLD
+
+REM BASE DLL.
+IF EXIST %CDS_DIR%\DLL_MAIN_CPP.BLD ( DEL /F /S /Q %CDS_DIR%\DLL_MAIN_CPP.BLD )
+IF EXIST %CDS_DIR%\DLL_MAIN_CPP.LKS ( DEL /F /S /Q %CDS_DIR%\DLL_MAIN_CPP.LKS )
+type %CDS_DIR%\NORMAL_ARGS.ARG > %CDS_DIR%\DLL_MAIN_CPP.BLD
+type %CDS_DIR%\DLL_MAIN_CPP.FLS >> %CDS_DIR%\DLL_MAIN_CPP.BLD
+type %CDS_DIR%\SC_DIFFERENT_DEPS.FLS >> %CDS_DIR%\DLL_MAIN_CPP.BLD
+type %CDS_DIR%\NORMAL_ARGS.ARG > %CDS_DIR%\DLL_MAIN_CPP.LKS
+type %CDS_DIR%\DLL_MAIN_CPP.OS >> %CDS_DIR%\DLL_MAIN_CPP.LKS
+
+REM EXPERIMENTAL.
+IF EXIST %CDS_DIR%\EXPERIMENTAL.BLD ( DEL /F /S /Q %CDS_DIR%\EXPERIMENTAL.BLD )
+IF EXIST %CDS_DIR%\EXPERIMENTAL.LKS ( DEL /F /S /Q %CDS_DIR%\EXPERIMENTAL.LKS )
+
+REM Note the order and repeats. cl will complain if this gets messed up.
+REM OLD SCRIPT.
+REM type NORMAL_ARGS.ARG > EXPERIMENTAL.BLD
+REM type EXPERIMENTAL.ARG >> EXPERIMENTAL.BLD
+REM type EXPERIMENTAL.ICD >> EXPERIMENTAL.BLD
+REM type DLL_MAIN_CPP.FLS >> EXPERIMENTAL.BLD
+REM type SC_DIFFERENT_DEPS.FLS >> EXPERIMENTAL.BLD
+REM type OVERLAY_EXPERIMENTAL.FLS >> EXPERIMENTAL.BLD
+REM type OVERLAY_EXPERIMENTAL_SYSTEM.FLS >> EXPERIMENTAL.BLD
+REM type DETOURS.FLS >> EXPERIMENTAL.BLD
+REM type CONTROLLER.FLS >> EXPERIMENTAL.BLD
+REM type IMGUI.FLS >> EXPERIMENTAL.BLD
+REM type NORMAL_ARGS.ARG > EXPERIMENTAL.LKS
+REM type EXPERIMENTAL.ARG >> EXPERIMENTAL.LKS
+REM type EXPERIMENTAL.ICD >> EXPERIMENTAL.LKS
+REM type DLL_MAIN_CPP.OS >> EXPERIMENTAL.LKS
+REM type EXPERIMENTAL.OS >> EXPERIMENTAL.LKS
+REM NEW Combined experimental && experimental_steamclient SCRIPT.
+type %CDS_DIR%\NORMAL_ARGS.ARG > %CDS_DIR%\EXPERIMENTAL.BLD
+type %CDS_DIR%\EXPERIMENTAL.ARG >> %CDS_DIR%\EXPERIMENTAL.BLD
+type %CDS_DIR%\OVERLAY_EXPERIMENTAL.ICD >> %CDS_DIR%\EXPERIMENTAL.BLD
+type %CDS_DIR%\IMGUI.ICD >> %CDS_DIR%\EXPERIMENTAL.BLD
+type %CDS_DIR%\SC_DIFFERENT_DEPS.FLS >> %CDS_DIR%\EXPERIMENTAL.BLD
+
+type %CDS_DIR%\NORMAL_ARGS.ARG > %CDS_DIR%\EXPERIMENTAL.LKS
+type %CDS_DIR%\EXPERIMENTAL.ARG >> %CDS_DIR%\EXPERIMENTAL.LKS
+type %CDS_DIR%\OVERLAY_EXPERIMENTAL.ICD >> %CDS_DIR%\EXPERIMENTAL.LKS
+type %CDS_DIR%\IMGUI.ICD >> %CDS_DIR%\EXPERIMENTAL.LKS
+type %CDS_DIR%\DLL_MAIN_CPP.OS >> %CDS_DIR%\EXPERIMENTAL.LKS
+type %CDS_DIR%\EXPERIMENTAL.OS >> %CDS_DIR%\EXPERIMENTAL.LKS
+
+REM SteamClient.
+IF EXIST %CDS_DIR%\STEAMCLIENT.BLD ( DEL /F /S /Q %CDS_DIR%\STEAMCLIENT.BLD )
+type %CDS_DIR%\NORMAL_ARGS.ARG > %CDS_DIR%\STEAMCLIENT.BLD
+type %CDS_DIR%\EXPERIMENTAL.ARG >> %CDS_DIR%\STEAMCLIENT.BLD
+type %CDS_DIR%\OVERLAY_EXPERIMENTAL.ICD >> %CDS_DIR%\STEAMCLIENT.BLD
+type %CDS_DIR%\IMGUI.ICD >> %CDS_DIR%\STEAMCLIENT.BLD
+type %CDS_DIR%\STEAMCLIENT.FLS >> %CDS_DIR%\STEAMCLIENT.BLD
+
+REM EXPERIMENTAL_STEAMCLIENT.
+IF EXIST %CDS_DIR%\EXPERIMENTAL_STEAMCLIENT.BLD ( DEL /F /S /Q %CDS_DIR%\EXPERIMENTAL_STEAMCLIENT.BLD )
+IF EXIST %CDS_DIR%\EXPERIMENTAL_STEAMCLIENT.LKS ( DEL /F /S /Q %CDS_DIR%\EXPERIMENTAL_STEAMCLIENT.LKS )
+
+REM Note the order and repeats. cl will complain if this gets messed up.
+
+
+
+
+REM FULL
+type %CDS_DIR%\NORMAL_ARGS.ARG > %CDS_DIR%\EXPERIMENTAL_STEAMCLIENT.LKS
+type %CDS_DIR%\EXPERIMENTAL.ARG >> %CDS_DIR%\EXPERIMENTAL_STEAMCLIENT.LKS
+type %CDS_DIR%\EXPERIMENTAL_STEAMCLIENT.ARG >> %CDS_DIR%\EXPERIMENTAL_STEAMCLIENT.LKS
+type %CDS_DIR%\SC_DIFFERENT_DEPS.FLS >> %CDS_DIR%\EXPERIMENTAL_STEAMCLIENT.LKS
+type %CDS_DIR%\DLL_MAIN_CPP.OS >> %CDS_DIR%\EXPERIMENTAL_STEAMCLIENT.LKS
+type %CDS_DIR%\EXPERIMENTAL.OS >> %CDS_DIR%\EXPERIMENTAL_STEAMCLIENT.LKS
+
+REM steamclient_loader.
+IF EXIST %CDS_DIR%\STEAMCLIENT_LOADER.BLD ( DEL /F /S /Q %CDS_DIR%\STEAMCLIENT_LOADER.BLD )
+IF EXIST %CDS_DIR%\STEAMCLIENT_LOADER.LKS ( DEL /F /S /Q %CDS_DIR%\STEAMCLIENT_LOADER.LKS )
+
+type %CDS_DIR%\NORMAL_ARGS.ARG > %CDS_DIR%\STEAMCLIENT_LOADER.BLD
+type %CDS_DIR%\STEAMCLIENT_LOADER.FLS >> %CDS_DIR%\STEAMCLIENT_LOADER.BLD
+
+type %CDS_DIR%\NORMAL_ARGS.ARG > %CDS_DIR%\STEAMCLIENT_LOADER.LKS
+type %CDS_DIR%\STEAMCLIENT_LOADER.OS >> %CDS_DIR%\STEAMCLIENT_LOADER.LKS
+
+REM lobby_connect.
+IF EXIST %CDS_DIR%\LOBBY_CONNECT.BLD ( DEL /F /S /Q %CDS_DIR%\LOBBY_CONNECT.BLD )
+IF EXIST %CDS_DIR%\LOBBY_CONNECT.LKS ( DEL /F /S /Q %CDS_DIR%\LOBBY_CONNECT.LKS )
+type %CDS_DIR%\LOBBY_CONNECT.ARG > %CDS_DIR%\LOBBY_CONNECT.BLD
+type %CDS_DIR%\NORMAL_ARGS.ARG >> %CDS_DIR%\LOBBY_CONNECT.BLD
+type %CDS_DIR%\LOBBY_CONNECT.FLS >> %CDS_DIR%\LOBBY_CONNECT.BLD
+type %CDS_DIR%\DLL_MAIN_CPP.FLS >> %CDS_DIR%\LOBBY_CONNECT.BLD
+type %CDS_DIR%\SC_DIFFERENT_DEPS.FLS >> %CDS_DIR%\LOBBY_CONNECT.BLD
+
+type %CDS_DIR%\LOBBY_CONNECT.ARG > %CDS_DIR%\LOBBY_CONNECT.LKS
+type %CDS_DIR%\NORMAL_ARGS.ARG >> %CDS_DIR%\LOBBY_CONNECT.LKS
+type %CDS_DIR%\DLL_MAIN_CPP.OS >> %CDS_DIR%\LOBBY_CONNECT.LKS
+type %CDS_DIR%\LOBBY_CONNECT.OS >> %CDS_DIR%\LOBBY_CONNECT.LKS
+
+REM GENERATE_INTERFACES_FILE
+IF EXIST %CDS_DIR%\GENERATE_INTERFACES_FILE.BLD ( DEL /F /S /Q %CDS_DIR%\GENERATE_INTERFACES_FILE.BLD )
+IF EXIST %CDS_DIR%\GENERATE_INTERFACES_FILE.LKS ( DEL /F /S /Q %CDS_DIR%\GENERATE_INTERFACES_FILE.LKS )
+type %CDS_DIR%\NORMAL_ARGS.ARG >> %CDS_DIR%\GENERATE_INTERFACES_FILE.BLD
+type %CDS_DIR%\GENERATE_INTERFACES_FILE.FLS >> %CDS_DIR%\GENERATE_INTERFACES_FILE.BLD
+
+type %CDS_DIR%\NORMAL_ARGS.ARG > %CDS_DIR%\GENERATE_INTERFACES_FILE.LKS
diff --git a/generate_build_win_bat.py b/generate_build_win_bat.py
deleted file mode 100644
index 9e3ef47..0000000
--- a/generate_build_win_bat.py
+++ /dev/null
@@ -1,132 +0,0 @@
-import os
-
-def files_from_dir(dir, extension, filter=[]):
- out = []
- for f in os.listdir(dir):
- if f.endswith(extension) and f not in filter:
- out.append(os.path.join(dir, f))
- return out
-
-def convert_to_obj(files, obj_dir):
- out = []
- for f in files:
- out.append(os.path.join(obj_dir, os.path.splitext(os.path.basename(f))[0] + ".obj"))
- return out
-
-def cl_line_obj(arguments, out_dir):
- return "rmdir /S /Q {0}\nmkdir {0}\ncl /Fo:{0}/ /c {1}\n".format(out_dir, ' '.join(arguments))
-
-def cl_line_link(arguments, linker_arguments):
- return "cl /LD {} /link {}\n".format(' '.join(arguments), ' '.join(linker_arguments))
-
-def cl_line_exe(arguments, linker_arguments):
- return "cl {} /link {}\n".format(' '.join(arguments), ' '.join(linker_arguments))
-
-jobs = 4
-normal_build_args = ["/EHsc", "/Ox", "/MP{}".format(jobs)]
-
-includes = ["ImGui", "overlay_experimental"]
-includes_32 = list(map(lambda a: '/I{}'.format(a), ["%PROTOBUF_X86_DIRECTORY%\\include\\"] + includes))
-includes_64 = list(map(lambda a: '/I{}'.format(a), ["%PROTOBUF_X64_DIRECTORY%\\include\\"] + includes))
-
-debug_build_args = []
-release_build_args = ["/DEMU_RELEASE_BUILD", "/DNDEBUG"]
-steamclient_build_args = ["/DSTEAMCLIENT_DLL"]
-lobby_connect_args = ["/DNO_DISK_WRITES", "/DLOBBY_CONNECT"]
-
-experimental_build_args = ["/DEMU_EXPERIMENTAL_BUILD", "/DCONTROLLER_SUPPORT", "/DEMU_OVERLAY"]
-steamclient_experimental_build_args = experimental_build_args + steamclient_build_args
-
-normal_linker_libs = ["Iphlpapi.lib", "Ws2_32.lib", "rtlgenrandom.lib", "Shell32.lib"]
-experimental_linker_libs = ["opengl32.lib", "Winmm.lib"] + normal_linker_libs
-linker_32 = ['"%PROTOBUF_X86_LIBRARY%"']
-linker_64 = ['"%PROTOBUF_X64_LIBRARY%"']
-
-controller_deps = ["controller/gamepad.c"]
-imgui_deps = files_from_dir("ImGui", ".cpp") + ["ImGui/backends/imgui_impl_dx9.cpp", "ImGui/backends/imgui_impl_dx10.cpp", "ImGui/backends/imgui_impl_dx11.cpp", "ImGui/backends/imgui_impl_dx12.cpp", "ImGui/backends/imgui_impl_win32.cpp", "ImGui/backends/imgui_impl_vulkan.cpp", "ImGui/backends/imgui_impl_opengl3.cpp", "ImGui/backends/imgui_win_shader_blobs.cpp"]
-proto_deps = list(map(lambda a: a.replace(".proto", ".pb.cc"), files_from_dir("dll", ".proto")))
-all_deps = proto_deps + files_from_dir("detours", ".cpp") + controller_deps + imgui_deps + files_from_dir("overlay_experimental/System", ".cpp")
-
-sc_different_deps = ["flat.cpp", "dll.cpp"]
-steam_deps = files_from_dir("dll", ".cpp", sc_different_deps)
-overlay_deps = files_from_dir("overlay_experimental", ".cpp") + files_from_dir("overlay_experimental/windows", ".cpp")
-experimental_steam_deps = steam_deps + overlay_deps
-sc_different_deps = list(map(lambda a: "dll/" + a, sc_different_deps))
-
-regular_files = []
-
-head = """@echo off
-cd /d "%~dp0"
-rmdir /S /Q release
-mkdir release
-mkdir release\experimental
-mkdir release\experimental_steamclient
-mkdir release\debug_experimental
-mkdir release\debug_experimental_steamclient
-mkdir release\lobby_connect
-call build_set_protobuf_directories.bat
-"""
-
-head_32bit = """"%PROTOC_X86_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\\net.proto
-call build_env_x86.bat
-cl dll/rtlgenrandom.c dll/rtlgenrandom.def
-"""
-
-head_64bit = """"%PROTOC_X64_EXE%" -I.\dll\ --cpp_out=.\dll\ .\dll\\net.proto
-call build_env_x64.bat
-cl dll/rtlgenrandom.c dll/rtlgenrandom.def
-"""
-
-footer = """
-copy Readme_release.txt release\Readme.txt
-xcopy /s files_example\* release\\
-copy Readme_experimental.txt release\experimental\Readme.txt
-copy Readme_debug.txt release\debug_experimental\Readme.txt
-copy steamclient_loader\ColdClientLoader.ini release\experimental_steamclient\\
-REM call build_win_lobby_connect.bat
-copy Readme_lobby_connect.txt release\lobby_connect\Readme.txt
-call build_win_find_interfaces.bat
-"""
-
-out = head
-out += head_32bit
-
-deps_folder = "deps"
-sc_deps_folder = "deps_sc"
-
-def generate_common(include_arch, linker_arch, steam_api_name, steamclient_name):
- out = ""
- out += cl_line_obj(normal_build_args + release_build_args + include_arch + all_deps, deps_folder)
- out += cl_line_link(normal_build_args + release_build_args + include_arch + steam_deps + sc_different_deps + ["deps/net.pb.obj"] + linker_arch + normal_linker_libs, ["/debug:none", "/OUT:release\\{}".format(steam_api_name)])
-
- debug_full_args = normal_build_args + debug_build_args + experimental_build_args + include_arch
- out += cl_line_obj(debug_full_args + experimental_steam_deps, sc_deps_folder)
-
- debug_full_dll_args = debug_full_args + sc_different_deps + convert_to_obj(all_deps, deps_folder) + convert_to_obj(experimental_steam_deps, sc_deps_folder) + linker_arch + experimental_linker_libs
- out += cl_line_link(debug_full_dll_args, ["/OUT:release\debug_experimental\\{}".format(steam_api_name)])
- out += cl_line_link(steamclient_build_args + debug_full_dll_args, ["/OUT:release\debug_experimental_steamclient\\{}".format(steamclient_name)])
-
- release_full_args = normal_build_args + release_build_args + experimental_build_args + include_arch
- out += cl_line_obj(release_full_args + experimental_steam_deps, sc_deps_folder)
-
- release_full_dll_args = release_full_args + sc_different_deps + convert_to_obj(all_deps, deps_folder) + convert_to_obj(experimental_steam_deps, sc_deps_folder) + linker_arch + experimental_linker_libs
- out += cl_line_link(release_full_dll_args, ["/debug:none", "/OUT:release\experimental\\{}".format(steam_api_name)])
- out += cl_line_link(steamclient_build_args + release_full_dll_args, ["/debug:none", "/OUT:release\experimental_steamclient\\{}".format(steamclient_name)])
- out += cl_line_link(release_build_args + experimental_build_args + ["steamclient.cpp"] + normal_build_args, ["/debug:none", "/OUT:release\experimental\\{}".format(steamclient_name)])
- return out
-
-out += generate_common(includes_32, linker_32, "steam_api.dll", "steamclient.dll")
-
-out += cl_line_exe(files_from_dir("./", "lobby_connect.cpp") + files_from_dir("dll", "flat.cpp") + files_from_dir("dll", "dll.cpp") + lobby_connect_args + normal_build_args + release_build_args + includes_32 + proto_deps + steam_deps + normal_linker_libs + ["Comdlg32.lib", "user32.lib"], linker_32 + ["/debug:none", "/OUT:release\lobby_connect\lobby_connect.exe"])
-
-out += cl_line_exe(files_from_dir("steamclient_loader", ".cpp") + ["advapi32.lib", "user32.lib"] + normal_build_args, ["/debug:none", "/OUT:release\experimental_steamclient\steamclient_loader.exe"])
-
-out += head_64bit
-out += generate_common(includes_64, linker_64, "steam_api64.dll", "steamclient64.dll")
-
-
-out += footer
-
-
-with open("build_win_release_test.bat", "w") as f:
- f.write(out)
From ae6e1829dd222b92c5d293d41bf6df9b8ac625eb Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Wed, 12 Feb 2025 09:32:46 -0500
Subject: [PATCH 17/67] CI: Use winehq.org's rpm until fedora 40 goes EOL.
Otherwise, we'll be constantly changing the URL in the CI yml everytime
Wine makes a new point release.
---
.gitlab-ci.yml | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 1a7612e..e054e77 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -66,11 +66,16 @@ build_windows:
- wget 'https://gitlab.com/Mr_Goldberg/goldberg_emulator/uploads/48db8f434a193aae872279dc4f5dde6a/sdk_standalone.7z'
- wget 'https://gitlab.com/Mr_Goldberg/goldberg_emulator/uploads/0119304e030098b4821d73170fe52084/protobuf_x64-windows-static.7z'
- wget 'https://gitlab.com/Mr_Goldberg/goldberg_emulator/uploads/4185a97ab363ddc1859127e59ec68581/protobuf_x86-windows-static.7z'
- # Ancient CI version of wine doesn't support the where.exe cmd. (It's a stub.) Use the version from wine-10.0.
- - wget 'https://dl.fedoraproject.org/pub/fedora/linux/updates/41/Everything/x86_64/Packages/w/wine-core-10.0-1.fc41.i686.rpm'
- mkdir wine
- - echo './usr/lib/wine/i386-windows/where.exe' > extract.txt; rpm2cpio wine-core-10.0-1.fc41.i686.rpm | cpio -ivdE extract.txt; rm -f extract.txt
- - /usr/bin/mv -f ./usr/lib/wine/i386-windows/where.exe wine/; rm -rf ./usr/
+ # Ancient CI version of wine doesn't support the where.exe cmd. (It's a stub.) Use the version from wine-10.1.
+ # Note: This can use the fedora archive once f40 goes eol (~ 5/28/2025) and wine 10.x gets locked into their archive server.
+ # (Can't use it before then due to newer wine point releases changing the URL....)
+ #- wget 'https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/39/Everything/x86_64/os/Packages/w/wine-core-10.0-1.fc41.i686.rpm'
+ #- echo './usr/lib/wine/i386-windows/where.exe' > extract.txt; rpm2cpio wine-core-10.0-1.fc41.i686.rpm | cpio -ivdE extract.txt; rm -f extract.txt
+ #- /usr/bin/mv -f ./usr/lib/wine/i386-windows/where.exe wine/; rm -rf ./usr/
+ - wget 'https://dl.winehq.org/wine-builds/fedora/41/x86_64/wine-devel-10.0.0-1.1.x86_64.rpm'
+ - echo './opt/wine-devel/lib64/wine/i386-windows/where.exe' > extract.txt; rpm2cpio wine-devel-10.0.0-1.1.x86_64.rpm | cpio -ivdE extract.txt; rm -f extract.txt
+ - /usr/bin/mv -f ./opt/wine-devel/lib64/wine/i386-windows/where.exe wine/; rm -rf ./opt/
- /usr/bin/cp -f wine/where.exe /usr/lib/wine/i386-windows/where.exe; /usr/bin/cp -f wine/where.exe /usr/lib64/wine/x86_64-windows/where.exe
- 7za x protobuf_x86-windows-static.7z -oprotobuf_x86-windows-static
- 7za x protobuf_x64-windows-static.7z -oprotobuf_x64-windows-static
From 8e8355c01318dda33495aac55e748f054d999cbc Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Fri, 7 Jun 2024 05:32:35 -0400
Subject: [PATCH 18/67] Add missing header include guards.
---
dll/appticket.h | 7 ++++++-
dll/steam_HTMLsurface.h | 5 +++++
dll/steam_applist.h | 5 +++++
dll/steam_apps.h | 5 +++++
dll/steam_client.h | 5 +++++
dll/steam_controller.h | 6 ++++++
dll/steam_game_coordinator.h | 5 +++++
dll/steam_gamesearch.h | 5 +++++
dll/steam_gameserver.h | 7 ++++++-
dll/steam_gameserverstats.h | 5 +++++
dll/steam_http.h | 4 ++++
dll/steam_inventory.h | 5 +++++
dll/steam_masterserver_updater.h | 5 +++++
dll/steam_matchmaking.h | 5 +++++
dll/steam_matchmaking_servers.h | 5 +++++
dll/steam_music.h | 5 +++++
dll/steam_musicremote.h | 5 +++++
dll/steam_networking.h | 5 +++++
dll/steam_networking_messages.h | 5 +++++
dll/steam_networking_sockets.h | 5 +++++
dll/steam_networking_socketsserialized.h | 5 +++++
dll/steam_networking_utils.h | 5 +++++
dll/steam_parental.h | 5 +++++
dll/steam_parties.h | 5 +++++
dll/steam_remote_storage.h | 5 +++++
dll/steam_remoteplay.h | 5 +++++
dll/steam_screenshots.h | 5 +++++
dll/steam_tv.h | 5 +++++
dll/steam_ugc.h | 5 +++++
dll/steam_unified_messages.h | 5 +++++
dll/steam_user.h | 5 +++++
dll/steam_utils.h | 5 +++++
dll/steam_video.h | 5 +++++
33 files changed, 167 insertions(+), 2 deletions(-)
diff --git a/dll/appticket.h b/dll/appticket.h
index 94f92e7..1768278 100644
--- a/dll/appticket.h
+++ b/dll/appticket.h
@@ -1,4 +1,7 @@
+#ifndef APPTICKET_H
+#define APPTICKET_H
+
struct AppTicketV1
{
// Total ticket size - 16
@@ -297,4 +300,6 @@ public:
return buffer;
}
-};
\ No newline at end of file
+};
+
+#endif // APPTICKET_H
diff --git a/dll/steam_HTMLsurface.h b/dll/steam_HTMLsurface.h
index 3b10b26..a35df54 100644
--- a/dll/steam_HTMLsurface.h
+++ b/dll/steam_HTMLsurface.h
@@ -17,6 +17,9 @@
#include "base.h"
+#ifndef INCLUDED_STEAM_HTMLSURFACE_H
+#define INCLUDED_STEAM_HTMLSURFACE_H
+
class Steam_HTMLsurface :
public ISteamHTMLSurface001,
public ISteamHTMLSurface002,
@@ -337,3 +340,5 @@ void FileLoadDialogResponse( HHTMLBrowser unBrowserHandle, const char **pchSelec
}
};
+
+#endif // INCLUDED_STEAM_HTMLSURFACE_H
diff --git a/dll/steam_applist.h b/dll/steam_applist.h
index 10f872e..1feb871 100644
--- a/dll/steam_applist.h
+++ b/dll/steam_applist.h
@@ -17,6 +17,9 @@
#include "base.h"
+#ifndef INCLUDED_STEAM_APPLIST_H
+#define INCLUDED_STEAM_APPLIST_H
+
class Steam_Applist : public ISteamAppList
{
public:
@@ -28,3 +31,5 @@ public:
int GetAppBuildId( AppId_t nAppID ); // return the buildid of this app, may change at any time based on backend updates to the game
};
+
+#endif // INCLUDED_STEAM_APPLIST_H
diff --git a/dll/steam_apps.h b/dll/steam_apps.h
index 1a4f206..eab3756 100644
--- a/dll/steam_apps.h
+++ b/dll/steam_apps.h
@@ -1,5 +1,8 @@
#include "base.h"
+#ifndef INCLUDED_STEAM_APPS_H
+#define INCLUDED_STEAM_APPS_H
+
class Steam_Apps :
public ISteamApps001,
public ISteamApps002,
@@ -110,3 +113,5 @@ public:
// set current DLC AppID being played (or 0 if none). Allows Steam to track usage of major DLC extensions
bool SetDlcContext( AppId_t nAppID );
};
+
+#endif // INCLUDED_STEAM_APPS_H
diff --git a/dll/steam_client.h b/dll/steam_client.h
index 37c4a85..9de5f95 100644
--- a/dll/steam_client.h
+++ b/dll/steam_client.h
@@ -53,6 +53,9 @@
#include "../overlay_experimental/steam_overlay.h"
+#ifndef INCLUDED_STEAM_CLIENT_H
+#define INCLUDED_STEAM_CLIENT_H
+
enum Steam_Pipe {
NO_USER,
CLIENT,
@@ -303,3 +306,5 @@ public:
void DestroyAllInterfaces();
};
+
+#endif // INCLUDED_STEAM_CLIENT_H
diff --git a/dll/steam_controller.h b/dll/steam_controller.h
index db04d60..b192b1c 100644
--- a/dll/steam_controller.h
+++ b/dll/steam_controller.h
@@ -16,6 +16,10 @@
. */
#include "base.h"
+
+#ifndef INCLUDED_STEAM_CONTROLLER_H
+#define INCLUDED_STEAM_CONTROLLER_H
+
#ifndef CONTROLLER_SUPPORT
inline void GamepadInit(void) {}
inline void GamepadShutdown(void) {}
@@ -1224,3 +1228,5 @@ void RunCallbacks()
}
};
+
+#endif // INCLUDED_STEAM_CONTROLLER_H
diff --git a/dll/steam_game_coordinator.h b/dll/steam_game_coordinator.h
index 1ba2b88..79f0edb 100644
--- a/dll/steam_game_coordinator.h
+++ b/dll/steam_game_coordinator.h
@@ -17,6 +17,9 @@
#include "base.h"
+#ifndef INCLUDED_STEAM_GAME_COORDINATOR_H
+#define INCLUDED_STEAM_GAME_COORDINATOR_H
+
class Steam_Game_Coordinator :
public ISteamGameCoordinator
{
@@ -152,3 +155,5 @@ void Callback(Common_Message *msg)
}
};
+
+#endif // INCLUDED_STEAM_GAME_COORDINATOR_H
diff --git a/dll/steam_gamesearch.h b/dll/steam_gamesearch.h
index 2254f01..dd06b6c 100644
--- a/dll/steam_gamesearch.h
+++ b/dll/steam_gamesearch.h
@@ -17,6 +17,9 @@
#include "base.h"
+#ifndef INCLUDED_STEAM_GAMESEARCH_H
+#define INCLUDED_STEAM_GAMESEARCH_H
+
class Steam_Game_Search :
public ISteamGameSearch
{
@@ -213,3 +216,5 @@ void Callback(Common_Message *msg)
}
};
+
+#endif // INCLUDED_STEAM_GAMESEARCH_H
diff --git a/dll/steam_gameserver.h b/dll/steam_gameserver.h
index 6cd9b70..8f385f2 100644
--- a/dll/steam_gameserver.h
+++ b/dll/steam_gameserver.h
@@ -16,7 +16,10 @@
. */
#include "base.h"
-
+
+#ifndef INCLUDED_STEAM_GAMESERVER_H
+#define INCLUDED_STEAM_GAMESERVER_H
+
//-----------------------------------------------------------------------------
// Purpose: Functions for authenticating users via Steam to play on a game server
//-----------------------------------------------------------------------------
@@ -353,3 +356,5 @@ public:
//
void RunCallbacks();
};
+
+#endif // INCLUDED_STEAM_GAMESERVER_H
diff --git a/dll/steam_gameserverstats.h b/dll/steam_gameserverstats.h
index 8efde54..b11e94a 100644
--- a/dll/steam_gameserverstats.h
+++ b/dll/steam_gameserverstats.h
@@ -17,6 +17,9 @@
#include "base.h"
+#ifndef INCLUDED_STEAM_GAMESERVERSTATS_H
+#define INCLUDED_STEAM_GAMESERVERSTATS_H
+
//-----------------------------------------------------------------------------
// Purpose: Functions for authenticating users via Steam to play on a game server
//-----------------------------------------------------------------------------
@@ -61,3 +64,5 @@ public:
STEAM_CALL_RESULT( GSStatsStored_t )
SteamAPICall_t StoreUserStats( CSteamID steamIDUser );
};
+
+#endif // INCLUDED_STEAM_GAMESERVERSTATS_H
diff --git a/dll/steam_http.h b/dll/steam_http.h
index 7e33f2c..c30d399 100644
--- a/dll/steam_http.h
+++ b/dll/steam_http.h
@@ -17,6 +17,8 @@
#include "base.h"
+#ifndef INCLUDED_STEAM_HTTP_H
+#define INCLUDED_STEAM_HTTP_H
struct Steam_Http_Request {
HTTPRequestHandle handle;
@@ -152,3 +154,5 @@ public:
// Check if the reason the request failed was because we timed it out (rather than some harder failure)
bool GetHTTPRequestWasTimedOut( HTTPRequestHandle hRequest, bool *pbWasTimedOut );
};
+
+#endif // INCLUDED_STEAM_HTTP_H
diff --git a/dll/steam_inventory.h b/dll/steam_inventory.h
index 4d30f20..699649c 100644
--- a/dll/steam_inventory.h
+++ b/dll/steam_inventory.h
@@ -17,6 +17,9 @@
#include "base.h" // For SteamItemDef_t
+#ifndef INCLUDED_STEAM_INVENTORY_H
+#define INCLUDED_STEAM_INVENTORY_H
+
struct Steam_Inventory_Requests {
double timeout = 0.1;
bool done = false;
@@ -964,3 +967,5 @@ void RunCallbacks()
}
};
+
+#endif // INCLUDED_STEAM_INVENTORY_H
diff --git a/dll/steam_masterserver_updater.h b/dll/steam_masterserver_updater.h
index d17ccd8..c08a6b6 100644
--- a/dll/steam_masterserver_updater.h
+++ b/dll/steam_masterserver_updater.h
@@ -17,6 +17,9 @@
#include "base.h"
+#ifndef INCLUDED_STEAM_MASTERSERVER_UPDATER_H
+#define INCLUDED_STEAM_MASTERSERVER_UPDATER_H
+
class Steam_Masterserver_Updater :
public ISteamMasterServerUpdater
{
@@ -300,3 +303,5 @@ void Callback(Common_Message *msg)
}
};
+
+#endif // INCLUDED_STEAM_MASTERSERVER_UPDATER_H
diff --git a/dll/steam_matchmaking.h b/dll/steam_matchmaking.h
index 94bd026..d3e1103 100644
--- a/dll/steam_matchmaking.h
+++ b/dll/steam_matchmaking.h
@@ -17,6 +17,9 @@
#include "base.h"
+#ifndef INCLUDED_STEAM_MATCHMAKING_H
+#define INCLUDED_STEAM_MATCHMAKING_H
+
#define SEND_LOBBY_RATE 5.0
#define PENDING_JOIN_TIMEOUT 10.0
@@ -1547,3 +1550,5 @@ void Callback(Common_Message *msg)
};
+
+#endif // INCLUDED_STEAM_MATCHMAKING_H
diff --git a/dll/steam_matchmaking_servers.h b/dll/steam_matchmaking_servers.h
index 21a643f..0650467 100644
--- a/dll/steam_matchmaking_servers.h
+++ b/dll/steam_matchmaking_servers.h
@@ -17,6 +17,9 @@
#include "base.h"
+#ifndef INCLUDED_STEAM_MATCHMAKING_SERVERS_H
+#define INCLUDED_STEAM_MATCHMAKING_SERVERS_H
+
#define SERVER_TIMEOUT 10.0
#define DIRECT_IP_DELAY 0.05
@@ -223,3 +226,5 @@ public:
void Callback(Common_Message *msg);
void server_details(Gameserver *g, gameserveritem_t *server);
};
+
+#endif // INCLUDED_STEAM_MATCHMAKING_SERVERS_H
diff --git a/dll/steam_music.h b/dll/steam_music.h
index 37ab94c..db2a6a8 100644
--- a/dll/steam_music.h
+++ b/dll/steam_music.h
@@ -17,6 +17,9 @@
#include "base.h"
+#ifndef INCLUDED_STEAM_MUSIC_H
+#define INCLUDED_STEAM_MUSIC_H
+
class Steam_Music : public ISteamMusic
{
int playing;
@@ -41,3 +44,5 @@ public:
void SetVolume( float flVolume );
float GetVolume();
};
+
+#endif // INCLUDED_STEAM_MUSIC_H
diff --git a/dll/steam_musicremote.h b/dll/steam_musicremote.h
index 4ad84c2..1cbfe85 100644
--- a/dll/steam_musicremote.h
+++ b/dll/steam_musicremote.h
@@ -17,6 +17,9 @@
#include "base.h"
+#ifndef INCLUDED_STEAM_MUSICREMOTE_H
+#define INCLUDED_STEAM_MUSICREMOTE_H
+
class Steam_MusicRemote : public ISteamMusicRemote
{
public:
@@ -65,3 +68,5 @@ public:
bool SetCurrentPlaylistEntry( int nID );
bool PlaylistDidChange();
};
+
+#endif // INCLUDED_STEAM_MUSICREMOTE_H
diff --git a/dll/steam_networking.h b/dll/steam_networking.h
index 4a19845..6b23acc 100644
--- a/dll/steam_networking.h
+++ b/dll/steam_networking.h
@@ -17,6 +17,9 @@
#include "base.h"
+#ifndef INCLUDED_STEAM_NETWORKING_H
+#define INCLUDED_STEAM_NETWORKING_H
+
//packet timeout in seconds for non connections
#define ORPHANED_PACKET_TIMEOUT (20)
#define NEW_CONNECTION_TIMEOUT (20.0)
@@ -1026,3 +1029,5 @@ void Callback(Common_Message *msg)
}
}
};
+
+#endif // INCLUDED_STEAM_NETWORKING_H
diff --git a/dll/steam_networking_messages.h b/dll/steam_networking_messages.h
index 38df49a..ed7a7e8 100644
--- a/dll/steam_networking_messages.h
+++ b/dll/steam_networking_messages.h
@@ -17,6 +17,9 @@
#include "base.h"
+#ifndef INCLUDED_STEAM_NETWORKING_MESSAGES
+#define INCLUDED_STEAM_NETWORKING_MESSAGES
+
#define NETWORKING_MESSAGES_TIMEOUT 30.0
struct Steam_Message_Connection {
@@ -444,3 +447,5 @@ void Callback(Common_Message *msg)
}
};
+
+#endif // INCLUDED_STEAM_NETWORKING_MESSAGES
diff --git a/dll/steam_networking_sockets.h b/dll/steam_networking_sockets.h
index 235e7bc..b2f1697 100644
--- a/dll/steam_networking_sockets.h
+++ b/dll/steam_networking_sockets.h
@@ -17,6 +17,9 @@
#include "base.h"
+#ifndef INCLUDED_STEAM_NETWORKING_SOCKETS_H
+#define INCLUDED_STEAM_NETWORKING_SOCKETS_H
+
struct Listen_Socket {
HSteamListenSocket socket_id;
@@ -2110,3 +2113,5 @@ void Callback(Common_Message *msg)
}
};
+
+#endif // INCLUDED_STEAM_NETWORKING_SOCKETS_H
diff --git a/dll/steam_networking_socketsserialized.h b/dll/steam_networking_socketsserialized.h
index 8b55292..30b5a2e 100644
--- a/dll/steam_networking_socketsserialized.h
+++ b/dll/steam_networking_socketsserialized.h
@@ -17,6 +17,9 @@
#include "base.h"
+#ifndef INCLUDED_STEAM_NETWORKING_SOCKETS_SERIALIZED_H
+#define INCLUDED_STEAM_NETWORKING_SOCKETS_SERIALIZED_H
+
class Steam_Networking_Sockets_Serialized :
public ISteamNetworkingSocketsSerialized002,
public ISteamNetworkingSocketsSerialized003,
@@ -154,3 +157,5 @@ void Callback(Common_Message *msg)
}
};
+
+#endif // INCLUDED_STEAM_NETWORKING_SOCKETS_SERIALIZED_H
diff --git a/dll/steam_networking_utils.h b/dll/steam_networking_utils.h
index 0e5388e..6897351 100644
--- a/dll/steam_networking_utils.h
+++ b/dll/steam_networking_utils.h
@@ -17,6 +17,9 @@
#include "base.h"
+#ifndef INCLUDED_STEAM_NETWORKING_UTILS_H
+#define INCLUDED_STEAM_NETWORKING_UTILS_H
+
class Steam_Networking_Utils :
public ISteamNetworkingUtils001,
public ISteamNetworkingUtils002,
@@ -749,3 +752,5 @@ void Callback(Common_Message *msg)
};
+
+#endif // INCLUDED_STEAM_NETWORKING_UTILS_H
diff --git a/dll/steam_parental.h b/dll/steam_parental.h
index 5505c61..5048541 100644
--- a/dll/steam_parental.h
+++ b/dll/steam_parental.h
@@ -17,6 +17,9 @@
#include "base.h"
+#ifndef INCLUDED_STEAM_PARENTAL_H
+#define INCLUDED_STEAM_PARENTAL_H
+
class Steam_Parental : public ISteamParentalSettings
{
public:
@@ -29,3 +32,5 @@ public:
bool BIsFeatureBlocked( EParentalFeature eFeature );
bool BIsFeatureInBlockList( EParentalFeature eFeature );
};
+
+#endif // INCLUDED_STEAM_PARENTAL_H
diff --git a/dll/steam_parties.h b/dll/steam_parties.h
index 8d282be..4dc1028 100644
--- a/dll/steam_parties.h
+++ b/dll/steam_parties.h
@@ -17,6 +17,9 @@
#include "base.h"
+#ifndef INCLUDED_STEAM_PARTIES_H
+#define INCLUDED_STEAM_PARTIES_H
+
class Steam_Parties :
public ISteamParties
{
@@ -192,3 +195,5 @@ void Callback(Common_Message *msg)
}
};
+
+#endif // INCLUDED_STEAM_PARTIES_H
diff --git a/dll/steam_remote_storage.h b/dll/steam_remote_storage.h
index 032bc5f..de6bf79 100644
--- a/dll/steam_remote_storage.h
+++ b/dll/steam_remote_storage.h
@@ -17,6 +17,9 @@
#include "base.h"
+#ifndef INCLUDED_STEAM_REMOTE_STORAGE_H
+#define INCLUDED_STEAM_REMOTE_STORAGE_H
+
struct Async_Read {
SteamAPICall_t api_call;
uint32 offset;
@@ -791,3 +794,5 @@ bool EndFileWriteBatch()
};
+
+#endif // INCLUDED_STEAM_REMOTE_STORAGE_H
diff --git a/dll/steam_remoteplay.h b/dll/steam_remoteplay.h
index 56e2965..c03ea4f 100644
--- a/dll/steam_remoteplay.h
+++ b/dll/steam_remoteplay.h
@@ -17,6 +17,9 @@
#include "base.h"
+#ifndef INCLUDED_STEAM_REMOTEPLAY_H
+#define INCLUDED_STEAM_REMOTEPLAY_H
+
class Steam_RemotePlay :
public ISteamRemotePlay
{
@@ -111,3 +114,5 @@ void Callback(Common_Message *msg)
}
};
+
+#endif // INCLUDED_STEAM_REMOTEPLAY_H
diff --git a/dll/steam_screenshots.h b/dll/steam_screenshots.h
index 745be9f..9acbe1f 100644
--- a/dll/steam_screenshots.h
+++ b/dll/steam_screenshots.h
@@ -17,6 +17,9 @@
#include "base.h"
+#ifndef INCLUDED_STEAM_SCREENSHOTS_H
+#define INCLUDED_STEAM_SCREENSHOTS_H
+
struct screenshot_infos_t
{
std::string screenshot_name;
@@ -73,3 +76,5 @@ public:
// JPEG, TGA, and PNG formats are supported.
ScreenshotHandle AddVRScreenshotToLibrary( EVRScreenshotType eType, const char *pchFilename, const char *pchVRFilename );
};
+
+#endif // INCLUDED_STEAM_SCREENSHOTS_H
diff --git a/dll/steam_tv.h b/dll/steam_tv.h
index 6ea7857..52738e3 100644
--- a/dll/steam_tv.h
+++ b/dll/steam_tv.h
@@ -17,6 +17,9 @@
#include "base.h"
+#ifndef INCLUDED_STEAM_TV_H
+#define INCLUDED_STEAM_TV_H
+
class Steam_TV :
public ISteamTV
{
@@ -122,3 +125,5 @@ void Callback(Common_Message *msg)
}
};
+
+#endif // INCLUDED_STEAM_TV_H
diff --git a/dll/steam_ugc.h b/dll/steam_ugc.h
index 77658b2..0b2785c 100644
--- a/dll/steam_ugc.h
+++ b/dll/steam_ugc.h
@@ -17,6 +17,9 @@
#include "base.h"
+#ifndef INCLUDED_STEAM_UGC_H
+#define INCLUDED_STEAM_UGC_H
+
struct UGC_query {
UGCQueryHandle_t handle;
std::set return_only;
@@ -903,3 +906,5 @@ SteamAPICall_t GetWorkshopEULAStatus()
};
+
+#endif // INCLUDED_STEAM_UGC_H
diff --git a/dll/steam_unified_messages.h b/dll/steam_unified_messages.h
index fb34fb7..b9169a1 100644
--- a/dll/steam_unified_messages.h
+++ b/dll/steam_unified_messages.h
@@ -17,6 +17,9 @@
#include "base.h"
+#ifndef INCLUDED_STEAM_UNIFIED_MESSAGES_H
+#define INCLUDED_STEAM_UNIFIED_MESSAGES_H
+
class Steam_Unified_Messages :
public ISteamUnifiedMessages
{
@@ -121,3 +124,5 @@ void Callback(Common_Message *msg)
}
};
+
+#endif // INCLUDED_STEAM_UNIFIED_MESSAGES_H
diff --git a/dll/steam_user.h b/dll/steam_user.h
index 0f21124..a316e17 100644
--- a/dll/steam_user.h
+++ b/dll/steam_user.h
@@ -19,6 +19,9 @@
#include "appticket.h"
+#ifndef INCLUDED_STEAM_USER_H
+#define INCLUDED_STEAM_USER_H
+
class Steam_User :
public ISteamUser009,
public ISteamUser010,
@@ -532,3 +535,5 @@ bool BSetDurationControlOnlineState( EDurationControlOnlineState eNewState )
}
};
+
+#endif // INCLUDED_STEAM_USER_H
diff --git a/dll/steam_utils.h b/dll/steam_utils.h
index d229cd3..b473d54 100644
--- a/dll/steam_utils.h
+++ b/dll/steam_utils.h
@@ -19,6 +19,9 @@
#include "local_storage.h"
#include "../overlay_experimental/steam_overlay.h"
+#ifndef INCLUDED_STEAM_UTILS_H
+#define INCLUDED_STEAM_UTILS_H
+
static std::chrono::time_point app_initialized_time = std::chrono::steady_clock::now();
@@ -442,3 +445,5 @@ bool DismissFloatingGamepadTextInput()
}
};
+
+#endif // INCLUDED_STEAM_UTILS_H
diff --git a/dll/steam_video.h b/dll/steam_video.h
index 9a1282d..0126ef5 100644
--- a/dll/steam_video.h
+++ b/dll/steam_video.h
@@ -17,6 +17,9 @@
#include "base.h"
+#ifndef INCLUDED_STEAM_VIDEO_H
+#define INCLUDED_STEAM_VIDEO_H
+
class Steam_Video : public ISteamVideo
{
public:
@@ -32,3 +35,5 @@ public:
void GetOPFSettings( AppId_t unVideoAppID );
bool GetOPFStringForApp( AppId_t unVideoAppID, char *pchBuffer, int32 *pnBufferSize );
};
+
+#endif // INCLUDED_STEAM_VIDEO_H
From 629473b53e522908776d785a8b16847e27a80b5c Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Sat, 8 Jun 2024 08:21:09 -0400
Subject: [PATCH 19/67] Set env:SteamAppPath in steamclient_loader.
---
steamclient_loader/ColdClientLoader.cpp | 3 +++
1 file changed, 3 insertions(+)
diff --git a/steamclient_loader/ColdClientLoader.cpp b/steamclient_loader/ColdClientLoader.cpp
index ed59f24..8b15871 100644
--- a/steamclient_loader/ColdClientLoader.cpp
+++ b/steamclient_loader/ColdClientLoader.cpp
@@ -127,6 +127,9 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
}
SetEvent(SharedMemFileLock);
+ // Create env.
+ SetEnvironmentVariableW(L"SteamAppPath", ExeRunDir);
+
WCHAR CommandLine[8192];
_snwprintf(CommandLine, _countof(CommandLine), L"\"%ls\" %ls", ExeFile, ExeCommandLine);
if (!ExeFile[0] || !CreateProcessW(ExeFile, CommandLine, NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, ExeRunDir, &info, &processInfo))
From e88f92cf4a89a253ea0549cf397f05ef2b64c290 Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Sun, 23 Jun 2024 22:27:38 -0400
Subject: [PATCH 20/67] Add 32bit registry view editing to ColdClientLoader.
---
steamclient_loader/ColdClientLoader.cpp | 37 +++++++++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/steamclient_loader/ColdClientLoader.cpp b/steamclient_loader/ColdClientLoader.cpp
index 8b15871..f322ff6 100644
--- a/steamclient_loader/ColdClientLoader.cpp
+++ b/steamclient_loader/ColdClientLoader.cpp
@@ -141,6 +141,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
return 0;
}
HKEY Registrykey;
+ HKEY Registrykey_32BitView;
// Declare some variables to be used for Steam registry.
DWORD UserId = 0x03100004771F810D & 0xffffffff;
DWORD ProcessID = GetCurrentProcessId();
@@ -149,8 +150,12 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
DWORD keyType = REG_SZ;
WCHAR OrgSteamCDir[MAX_PATH] = { 0 };
WCHAR OrgSteamCDir64[MAX_PATH] = { 0 };
+ WCHAR OrgSteamCDir_32BitView[MAX_PATH] = { 0 };
+ WCHAR OrgSteamCDir64_32BitView[MAX_PATH] = { 0 };
DWORD Size1 = MAX_PATH;
DWORD Size2 = MAX_PATH;
+ DWORD Size3 = MAX_PATH;
+ DWORD Size4 = MAX_PATH;
if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Valve\\Steam\\ActiveProcess", 0, KEY_ALL_ACCESS, &Registrykey) == ERROR_SUCCESS)
{
orig_steam = true;
@@ -169,30 +174,53 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
return 0;
}
}
+ if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Valve\\Steam\\ActiveProcess", 0, KEY_ALL_ACCESS | KEY_WOW64_32KEY, &Registrykey_32BitView) == ERROR_SUCCESS)
+ {
+ orig_steam = true;
+ // Get original values to restore later.
+ RegQueryValueExW(Registrykey_32BitView, L"SteamClientDll", 0, &keyType, (LPBYTE)& OrgSteamCDir_32BitView, &Size3);
+ RegQueryValueExW(Registrykey_32BitView, L"SteamClientDll64", 0, &keyType, (LPBYTE)& OrgSteamCDir64_32BitView, &Size4);
+ } else {
+ if (RegCreateKeyExW(HKEY_CURRENT_USER, L"Software\\Valve\\Steam\\ActiveProcess", 0, 0, REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS | KEY_WOW64_32KEY, NULL, &Registrykey_32BitView, NULL) != ERROR_SUCCESS)
+ {
+ MessageBoxA(NULL, "Unable to patch Steam process informations on the Windows registry.", "ColdClientLoader", MB_ICONERROR);
+ TerminateProcess(processInfo.hProcess, NULL);
+ return 0;
+ }
+ }
// Set values to Windows registry.
RegSetValueExA(Registrykey, "ActiveUser", NULL, REG_DWORD, (LPBYTE)& UserId, sizeof(DWORD));
RegSetValueExA(Registrykey, "pid", NULL, REG_DWORD, (LPBYTE)& ProcessID, sizeof(DWORD));
+ RegSetValueExA(Registrykey_32BitView, "ActiveUser", NULL, REG_DWORD, (LPBYTE)& UserId, sizeof(DWORD));
+ RegSetValueExA(Registrykey_32BitView, "pid", NULL, REG_DWORD, (LPBYTE)& ProcessID, sizeof(DWORD));
{
// Before saving to the registry check again if the path was valid and if the file exist
if (GetFileAttributesW(ClientPath) != INVALID_FILE_ATTRIBUTES) {
RegSetValueExW(Registrykey, L"SteamClientDll", NULL, REG_SZ, (LPBYTE)ClientPath, (DWORD)(lstrlenW(ClientPath) * sizeof(WCHAR)) + 1);
+ RegSetValueExW(Registrykey_32BitView, L"SteamClientDll", NULL, REG_SZ, (LPBYTE)ClientPath, (DWORD)(lstrlenW(ClientPath) * sizeof(WCHAR)) + 1);
}
else {
RegSetValueExW(Registrykey, L"SteamClientDll", NULL, REG_SZ, (LPBYTE)"", 0);
+ RegSetValueExW(Registrykey_32BitView, L"SteamClientDll", NULL, REG_SZ, (LPBYTE)"", 0);
}
if (GetFileAttributesW(Client64Path) != INVALID_FILE_ATTRIBUTES) {
RegSetValueExW(Registrykey, L"SteamClientDll64", NULL, REG_SZ, (LPBYTE)Client64Path, (DWORD)(lstrlenW(Client64Path) * sizeof(WCHAR)) + 1);
+ RegSetValueExW(Registrykey_32BitView, L"SteamClientDll64", NULL, REG_SZ, (LPBYTE)Client64Path, (DWORD)(lstrlenW(Client64Path) * sizeof(WCHAR)) + 1);
}
else {
RegSetValueExW(Registrykey, L"SteamClientDll64", NULL, REG_SZ, (LPBYTE)"", 0);
+ RegSetValueExW(Registrykey_32BitView, L"SteamClientDll64", NULL, REG_SZ, (LPBYTE)"", 0);
}
}
RegSetValueExA(Registrykey, "Universe", NULL, REG_SZ, (LPBYTE)"Public", (DWORD)lstrlenA("Public") + 1);
+ RegSetValueExA(Registrykey_32BitView, "Universe", NULL, REG_SZ, (LPBYTE)"Public", (DWORD)lstrlenA("Public") + 1);
// Close the HKEY Handle.
RegCloseKey(Registrykey);
+ RegCloseKey(Registrykey_32BitView);
ResumeThread(processInfo.hThread);
WaitForSingleObject(processInfo.hThread, INFINITE);
@@ -209,6 +237,15 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
// Close the HKEY Handle.
RegCloseKey(Registrykey);
}
+ if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Valve\\Steam\\ActiveProcess", 0, KEY_ALL_ACCESS | KEY_WOW64_32KEY, &Registrykey_32BitView) == ERROR_SUCCESS)
+ {
+ // Restore the values.
+ RegSetValueExW(Registrykey_32BitView, L"SteamClientDll", NULL, REG_SZ, (LPBYTE)OrgSteamCDir_32BitView, Size3);
+ RegSetValueExW(Registrykey_32BitView, L"SteamClientDll64", NULL, REG_SZ, (LPBYTE)OrgSteamCDir64_32BitView, Size4);
+
+ // Close the HKEY Handle.
+ RegCloseKey(Registrykey_32BitView);
+ }
}
// Close the SharedMem handles.
From e767bb9fe9047f1c21103b7244fd58a1052d298f Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Mon, 24 Jun 2024 02:06:58 -0400
Subject: [PATCH 21/67] Add inttypes defs to common_includes.h
---
dll/common_includes.h | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/dll/common_includes.h b/dll/common_includes.h
index 3b43545..bf9b815 100644
--- a/dll/common_includes.h
+++ b/dll/common_includes.h
@@ -65,6 +65,18 @@
#include
#undef SystemFunction036
+ #ifdef _MSC_VER
+ #ifndef PRIu64
+ #define PRIu64 "I64u"
+ #endif
+ #ifndef PRIuPTR
+ #define PRIuPTR "Iu"
+ #endif
+ #define PRI_ZU "Iu" // Format specifier for size_t.
+ #else
+ #include
+ #endif
+
#ifndef EMU_RELEASE_BUILD
#define PRINT_DEBUG(a, ...) do {FILE *t = fopen("STEAM_LOG.txt", "a"); fprintf(t, "%u " a, GetCurrentThreadId(), __VA_ARGS__); fclose(t); WSASetLastError(0);} while (0)
#endif
@@ -126,6 +138,9 @@ inline void reset_LastError()
#include
#include
+ #include
+ #define PRI_ZU "zu"
+
#define PATH_MAX_STRING_SIZE 512
#ifndef EMU_RELEASE_BUILD
From c9236a73376a765409b780247f3dac325b605b53 Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Mon, 24 Jun 2024 02:48:22 -0400
Subject: [PATCH 22/67] Fix compiler warnings.
---
dll/local_storage.cpp | 2 +-
dll/network.cpp | 2 +-
dll/settings_parser.cpp | 2 +-
dll/steam_matchmaking_servers.cpp | 4 ++--
dll/steam_networking_sockets.h | 6 +++---
dll/steam_networking_utils.h | 2 +-
6 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/dll/local_storage.cpp b/dll/local_storage.cpp
index f6ab1fc..1c333b8 100644
--- a/dll/local_storage.cpp
+++ b/dll/local_storage.cpp
@@ -717,7 +717,7 @@ bool Local_Storage::load_json(std::string full_path, nlohmann::json& json)
try {
json = std::move(nlohmann::json::parse(buffer));
- PRINT_DEBUG("Loaded json \"%s\". Loaded %u items.\n", full_path.c_str(), json.size());
+ PRINT_DEBUG("Loaded json \"%s\". Loaded %" PRI_ZU " items.\n", full_path.c_str(), json.size());
return true;
} catch (std::exception& e) {
PRINT_DEBUG("Error while parsing \"%s\" json: %s\n", full_path.c_str(), e.what());
diff --git a/dll/network.cpp b/dll/network.cpp
index c7323c6..9006fce 100644
--- a/dll/network.cpp
+++ b/dll/network.cpp
@@ -513,7 +513,7 @@ std::set Networking::resolve_ip(std::string dns)
if (getaddrinfo(dns.c_str(), NULL, NULL, &result) == 0) {
for (struct addrinfo *res = result; res != NULL; res = res->ai_next) {
- PRINT_DEBUG("%u %u\n", res->ai_addrlen, res->ai_family);
+ PRINT_DEBUG("%" PRI_ZU " %u\n", res->ai_addrlen, res->ai_family);
if (res->ai_family == AF_INET) {
struct sockaddr_in *ipv4 = (struct sockaddr_in *)res->ai_addr;
uint32 ip;
diff --git a/dll/settings_parser.cpp b/dll/settings_parser.cpp
index af56f73..87ec1d7 100644
--- a/dll/settings_parser.cpp
+++ b/dll/settings_parser.cpp
@@ -110,7 +110,7 @@ static void load_gamecontroller_settings(Settings *settings)
}
settings->controller_settings.action_sets[action_set_name] = button_pairs;
- PRINT_DEBUG("Added %u action names to %s\n", button_pairs.size(), action_set_name.c_str());
+ PRINT_DEBUG("Added %" PRI_ZU " action names to %s\n", button_pairs.size(), action_set_name.c_str());
}
}
diff --git a/dll/steam_matchmaking_servers.cpp b/dll/steam_matchmaking_servers.cpp
index 23441f3..c436ee6 100644
--- a/dll/steam_matchmaking_servers.cpp
+++ b/dll/steam_matchmaking_servers.cpp
@@ -33,7 +33,7 @@ Steam_Matchmaking_Servers::Steam_Matchmaking_Servers(class Settings *settings, c
this->network->setCallback(CALLBACK_ID_GAMESERVER, (uint64) 0, &network_callback, this);
}
-static int server_list_request;
+static size_t server_list_request;
// Request a new list of servers of a particular type. These calls each correspond to one of the EMatchMakingType values.
// Each call allocates a new asynchronous request object.
@@ -297,7 +297,7 @@ gameserveritem_t *Steam_Matchmaking_Servers::GetServerDetails( HServerListReques
PRINT_DEBUG("equal? %p %p\n", hRequest, g->id);
if (g->id == hRequest) {
gameservers_filtered = g->gameservers_filtered;
- PRINT_DEBUG("found %u\n", gameservers_filtered.size());
+ PRINT_DEBUG("found %" PRI_ZU "\n", gameservers_filtered.size());
break;
}
diff --git a/dll/steam_networking_sockets.h b/dll/steam_networking_sockets.h
index b2f1697..8c11a08 100644
--- a/dll/steam_networking_sockets.h
+++ b/dll/steam_networking_sockets.h
@@ -884,7 +884,7 @@ SteamNetworkingMessage_t *get_steam_message_connection(HSteamNetConnection hConn
pMsg->m_pfnRelease = &delete_steam_message;
pMsg->m_nChannel = 0;
connect_socket->second.data.pop();
- PRINT_DEBUG("get_steam_message_connection %u %u, %u\n", hConn, size, pMsg->m_nMessageNumber);
+ PRINT_DEBUG("get_steam_message_connection %u, %u, %" PRIu64 "\n", hConn, size, pMsg->m_nMessageNumber);
return pMsg;
}
@@ -2089,13 +2089,13 @@ void Callback(Common_Message *msg)
auto connect_socket = s->connect_sockets.find(msg->networking_sockets().connection_id());
if (connect_socket != s->connect_sockets.end()) {
if (connect_socket->second.remote_identity.GetSteamID64() == msg->source_id() && (connect_socket->second.status == CONNECT_SOCKET_CONNECTED)) {
- PRINT_DEBUG("Steam_Networking_Sockets: got data len %u, num %u on connection %u\n", msg->networking_sockets().data().size(), msg->networking_sockets().message_number(), connect_socket->first);
+ PRINT_DEBUG("Steam_Networking_Sockets: got data len %" PRI_ZU ", num %" PRIu64 " on connection %u\n", msg->networking_sockets().data().size(), msg->networking_sockets().message_number(), connect_socket->first);
connect_socket->second.data.push(msg->networking_sockets());
}
} else {
connect_socket = std::find_if(s->connect_sockets.begin(), s->connect_sockets.end(), [msg](const auto &in) {return in.second.remote_identity.GetSteamID64() == msg->source_id() && (in.second.status == CONNECT_SOCKET_NOT_ACCEPTED || in.second.status == CONNECT_SOCKET_CONNECTED) && in.second.remote_id == msg->networking_sockets().connection_id_from();});
if (connect_socket != s->connect_sockets.end()) {
- PRINT_DEBUG("Steam_Networking_Sockets: got data len %u, num %u on not accepted connection %u\n", msg->networking_sockets().data().size(), msg->networking_sockets().message_number(), connect_socket->first);
+ PRINT_DEBUG("Steam_Networking_Sockets: got data len %" PRI_ZU ", num %" PRIu64 " on not accepted connection %u\n", msg->networking_sockets().data().size(), msg->networking_sockets().message_number(), connect_socket->first);
connect_socket->second.data.push(msg->networking_sockets());
}
}
diff --git a/dll/steam_networking_utils.h b/dll/steam_networking_utils.h
index 6897351..322adde 100644
--- a/dll/steam_networking_utils.h
+++ b/dll/steam_networking_utils.h
@@ -361,7 +361,7 @@ bool SetConnectionConfigValueString( HSteamNetConnection hConn, ESteamNetworking
bool SetConfigValue( ESteamNetworkingConfigValue eValue, ESteamNetworkingConfigScope eScopeType, intptr_t scopeObj,
ESteamNetworkingConfigDataType eDataType, const void *pArg )
{
- PRINT_DEBUG("Steam_Networking_Utils::SetConfigValue %i %i %p %i %p\n", eValue, eScopeType, scopeObj, eDataType, pArg);
+ PRINT_DEBUG("Steam_Networking_Utils::SetConfigValue %i %i %" PRIuPTR " %i %p\n", eValue, eScopeType, scopeObj, eDataType, pArg);
return true;
}
From a8c696c565106d2324913bbcdcbef0271767674b Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Mon, 24 Jun 2024 03:57:16 -0400
Subject: [PATCH 23/67] Fix detours not attaching to all threads on startup.
---
dll/base.cpp | 49 ++++++++++++++++++++++++++++++++++++++++---
dll/common_includes.h | 1 +
2 files changed, 47 insertions(+), 3 deletions(-)
diff --git a/dll/base.cpp b/dll/base.cpp
index 10d3622..5363e6d 100644
--- a/dll/base.cpp
+++ b/dll/base.cpp
@@ -841,16 +841,55 @@ HINTERNET WINAPI Mine_WinHttpOpenRequest(
return Real_WinHttpOpenRequest(hConnect, pwszVerb, pwszObjectName, pwszVersion, pwszReferrer, ppwszAcceptTypes, dwFlags);
}
-
-
static bool network_functions_attached = false;
+std::vector detours_threads;
+
BOOL WINAPI DllMain( HINSTANCE, DWORD dwReason, LPVOID ) {
switch ( dwReason ) {
case DLL_PROCESS_ATTACH:
if (!file_exists(get_full_program_path() + "disable_lan_only.txt") && !file_exists(get_full_program_path() + "\\steam_settings\\disable_lan_only.txt")) {
PRINT_DEBUG("Hooking lan only functions\n");
DetourTransactionBegin();
- DetourUpdateThread( GetCurrentThread() );
+ HANDLE toolHelp = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
+ if (toolHelp != INVALID_HANDLE_VALUE) {
+ THREADENTRY32 te;
+ te.dwSize = sizeof(THREADENTRY32);
+ if (Thread32First(toolHelp, &te)) {
+ bool bUpdatedThread = false;
+ DWORD myPID = GetCurrentProcessId();
+ DWORD myTID = GetCurrentThreadId();
+ HANDLE tHandle;
+ do {
+ if (te.dwSize >= FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(te.th32OwnerProcessID)) {
+ if (te.th32OwnerProcessID == myPID) {
+ if (te.th32ThreadID != myTID) {
+ tHandle = OpenThread(THREAD_ALL_ACCESS, false, te.th32ThreadID);
+ if (tHandle != NULL) {
+ PRINT_DEBUG("Hooking thread %d\n", te.th32ThreadID);
+ detours_threads.push_back( tHandle );
+ DetourUpdateThread( tHandle );
+ bUpdatedThread = true;
+ } else {
+ PRINT_DEBUG("Unable to hook thread %d\n", te.th32ThreadID);
+ }
+ } else {//hooking non-pseudo current thread handle is unsupported.
+ PRINT_DEBUG("Hooking thread %d\n", myTID);
+ DetourUpdateThread( GetCurrentThread() );
+ bUpdatedThread = true;
+ }
+ }
+ }
+ te.dwSize = sizeof(THREADENTRY32);
+ } while (Thread32Next(toolHelp, &te));
+ } else {
+ PRINT_DEBUG("Unable to iterate thread list, only hooking current thread\n");
+ DetourUpdateThread( GetCurrentThread() );
+ }
+ CloseHandle(toolHelp);
+ } else {
+ PRINT_DEBUG("Unable to get thread list, only hooking current thread\n");
+ DetourUpdateThread( GetCurrentThread() );
+ }
DetourAttach( &(PVOID &)Real_SendTo, Mine_SendTo );
DetourAttach( &(PVOID &)Real_Connect, Mine_Connect );
DetourAttach( &(PVOID &)Real_WSAConnect, Mine_WSAConnect );
@@ -871,8 +910,12 @@ BOOL WINAPI DllMain( HINSTANCE, DWORD dwReason, LPVOID ) {
break;
case DLL_PROCESS_DETACH:
+ std::vector::iterator it;
if (network_functions_attached) {
DetourTransactionBegin();
+ for (it = detours_threads.begin(); it != detours_threads.end(); it++) {
+ DetourUpdateThread( *it );
+ }
DetourUpdateThread( GetCurrentThread() );
DetourDetach( &(PVOID &)Real_SendTo, Mine_SendTo );
DetourDetach( &(PVOID &)Real_Connect, Mine_Connect );
diff --git a/dll/common_includes.h b/dll/common_includes.h
index bf9b815..cf3e4c7 100644
--- a/dll/common_includes.h
+++ b/dll/common_includes.h
@@ -86,6 +86,7 @@
#ifdef EMU_EXPERIMENTAL_BUILD
#include
+ #include
#include "../detours/detours.h"
#endif
From a1ec70d3b0b02ccf2c96bc347d2988660744b8c9 Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Mon, 24 Jun 2024 05:45:46 -0400
Subject: [PATCH 24/67] Fix memory leak in resolve_ip.
---
dll/network.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/dll/network.cpp b/dll/network.cpp
index 9006fce..4f0d026 100644
--- a/dll/network.cpp
+++ b/dll/network.cpp
@@ -524,6 +524,7 @@ std::set Networking::resolve_ip(std::string dns)
ips.insert(addr);
}
}
+ freeaddrinfo(result);
}
return ips;
From dfc486dd3b68a10c4c6cbe206c3883b845fa49df Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Fri, 15 Nov 2024 12:50:31 -0500
Subject: [PATCH 25/67] Add functions for global flag settings, ...
return width and height for loaded images.
---
dll/local_storage.cpp | 60 +++++++++++++++++++++++++++++++++++++------
dll/local_storage.h | 5 +++-
2 files changed, 56 insertions(+), 9 deletions(-)
diff --git a/dll/local_storage.cpp b/dll/local_storage.cpp
index 1c333b8..c8d1a33 100644
--- a/dll/local_storage.cpp
+++ b/dll/local_storage.cpp
@@ -156,7 +156,7 @@ std::vector Local_Storage::get_filenames_path(std::string path)
return std::vector();
}
-std::vector Local_Storage::load_image(std::string const& image_path)
+std::vector Local_Storage::load_image(std::string const& image_path, uint32_t * out_width, uint32_t * out_height)
{
return std::vector();
}
@@ -612,6 +612,14 @@ bool Local_Storage::file_exists(std::string folder, std::string file)
return file_exists_(full_path);
}
+bool Local_Storage::data_settings_exists(std::string file)
+{
+ file = sanitize_file_name(file);
+
+ std::string full_path = get_global_settings_path() + file;
+ return file_exists_(full_path);
+}
+
unsigned int Local_Storage::file_size(std::string folder, std::string file)
{
file = sanitize_file_name(file);
@@ -623,6 +631,23 @@ unsigned int Local_Storage::file_size(std::string folder, std::string file)
return file_size_(full_path);
}
+unsigned int Local_Storage::data_settings_size(std::string file)
+{
+ file = sanitize_file_name(file);
+
+ std::string full_path = get_global_settings_path() + file;
+ return file_size_(full_path);
+}
+
+bool _internal_file_delete(std::string & full_path)
+{
+#if defined(STEAM_WIN32)
+ return _wremove(utf8_decode(full_path).c_str()) == 0;
+#else
+ return remove(full_path.c_str()) == 0;
+#endif
+}
+
bool Local_Storage::file_delete(std::string folder, std::string file)
{
file = sanitize_file_name(file);
@@ -631,11 +656,15 @@ bool Local_Storage::file_delete(std::string folder, std::string file)
}
std::string full_path = save_directory + appid + folder + file;
-#if defined(STEAM_WIN32)
- return _wremove(utf8_decode(full_path).c_str()) == 0;
-#else
- return remove(full_path.c_str()) == 0;
-#endif
+ return _internal_file_delete(full_path);
+}
+
+bool Local_Storage::delete_data_settings(std::string file)
+{
+ file = sanitize_file_name(file);
+
+ std::string full_path = get_global_settings_path() + file;
+ return _internal_file_delete(full_path);
}
uint64_t Local_Storage::file_timestamp(std::string folder, std::string file)
@@ -766,10 +795,11 @@ bool Local_Storage::write_json_file(std::string folder, std::string const&file,
return false;
}
-std::vector Local_Storage::load_image(std::string const& image_path)
+std::vector Local_Storage::load_image(std::string const& image_path, uint32_t * out_width, uint32_t * out_height)
{
std::vector res;
- int width, height;
+ int32_t width = 0;
+ int32_t height = 0;
image_pixel_t* img = (image_pixel_t*)stbi_load(image_path.c_str(), &width, &height, nullptr, 4);
if (img != nullptr)
{
@@ -778,6 +808,20 @@ std::vector Local_Storage::load_image(std::string const& image_pa
stbi_image_free(img);
}
+ if (out_width != nullptr) {
+ if (width > 0) {
+ *out_width = static_cast(width);
+ } else {
+ *out_width = 0;
+ }
+ }
+ if (out_height != nullptr) {
+ if (height > 0) {
+ *out_height = static_cast(height);
+ } else {
+ *out_height = 0;
+ }
+ }
reset_LastError();
return res;
diff --git a/dll/local_storage.h b/dll/local_storage.h
index ddb1c33..ae7b6aa 100644
--- a/dll/local_storage.h
+++ b/dll/local_storage.h
@@ -72,8 +72,11 @@ public:
int count_files(std::string folder);
bool iterate_file(std::string folder, int index, char *output_filename, int32 *output_size);
bool file_exists(std::string folder, std::string file);
+ bool data_settings_exists(std::string file);
unsigned int file_size(std::string folder, std::string file);
+ unsigned int data_settings_size(std::string file);
bool file_delete(std::string folder, std::string file);
+ bool delete_data_settings(std::string file);
uint64_t file_timestamp(std::string folder, std::string file);
std::string get_global_settings_path();
std::string get_path(std::string folder);
@@ -84,7 +87,7 @@ public:
bool load_json_file(std::string folder, std::string const& file, nlohmann::json& json);
bool write_json_file(std::string folder, std::string const& file, nlohmann::json const& json);
- std::vector load_image(std::string const& image_path);
+ std::vector load_image(std::string const& image_path, uint32_t * out_width, uint32_t * out_height);
bool save_screenshot(std::string const& image_path, uint8_t* img_ptr, int32_t width, int32_t height, int32_t channels);
};
From 662e22bade5fa88e925984ad2575ea686b6ff82a Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Fri, 15 Nov 2024 12:53:30 -0500
Subject: [PATCH 26/67] Add some achievement display settings.
---
dll/settings.h | 8 ++++++++
dll/steam_screenshots.cpp | 2 +-
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/dll/settings.h b/dll/settings.h
index aeb8b49..8528895 100644
--- a/dll/settings.h
+++ b/dll/settings.h
@@ -73,6 +73,8 @@ class Settings {
bool unlockAllDLCs;
bool offline;
+ bool showAchievementDescOnUnlock;
+ bool showAchievementHiddenUnearned;
std::vector DLCs;
std::vector mods;
std::map app_paths;
@@ -170,6 +172,12 @@ public:
//warn people who use local save
bool warn_local_save = false;
+
+ //achievements
+ bool get_show_achievement_desc_on_unlock() { return showAchievementDescOnUnlock; }
+ void set_show_achievement_desc_on_unlock(bool set) { this->showAchievementDescOnUnlock = set; }
+ bool get_show_achievement_hidden_unearned() { return showAchievementHiddenUnearned; }
+ void set_show_achievement_hidden_unearned(bool set) { this->showAchievementHiddenUnearned = set; }
};
#endif
diff --git a/dll/steam_screenshots.cpp b/dll/steam_screenshots.cpp
index f4e0d45..5eca0d2 100644
--- a/dll/steam_screenshots.cpp
+++ b/dll/steam_screenshots.cpp
@@ -65,7 +65,7 @@ ScreenshotHandle Steam_Screenshots::AddScreenshotToLibrary( const char *pchFilen
if (pchFilename == nullptr)
return INVALID_SCREENSHOT_HANDLE;
- std::vector pixels(std::move(local_storage->load_image(pchFilename)));
+ std::vector pixels(std::move(local_storage->load_image(pchFilename, NULL, NULL)));
if (pixels.size() != size_t(nWidth) * size_t(nHeight))
return INVALID_SCREENSHOT_HANDLE;
From 8029c41c043616ccd918127a723bd56922bb19d4 Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Fri, 15 Nov 2024 12:58:21 -0500
Subject: [PATCH 27/67] Implement ISteamUserStats::GetAchievementIcon().
---
dll/steam_user_stats.h | 78 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 76 insertions(+), 2 deletions(-)
diff --git a/dll/steam_user_stats.h b/dll/steam_user_stats.h
index 4ff4163..ff42133 100644
--- a/dll/steam_user_stats.h
+++ b/dll/steam_user_stats.h
@@ -85,6 +85,8 @@ private:
nlohmann::json defined_achievements;
nlohmann::json user_achievements;
std::vector sorted_achievement_names;
+ std::map achievement_image_data_normal;
+ std::map achievement_image_data_gray;
std::map stats_cache_int;
std::map stats_cache_float;
@@ -112,10 +114,74 @@ nlohmann::detail::iter_impl defined_achievements_find(std::strin
});
}
+int32 achievement_image_data_normal_find(std::string key) {
+ for (auto & it : achievement_image_data_normal) {
+ try {
+ if (it.first == key) {
+ return it.second;
+ }
+ } catch (...) {}
+ }
+ return 0;
+}
+
+int32 achievement_image_data_gray_find(std::string key) {
+ for (auto & it : achievement_image_data_gray) {
+ try {
+ if (it.first == key) {
+ return it.second;
+ }
+ } catch (...) {}
+ }
+ return 0;
+}
+
void load_achievements_db()
{
+ uint64 count = 0;
std::string file_path = Local_Storage::get_game_settings_path() + achievements_user_file;
local_storage->load_json(file_path, defined_achievements);
+ for (auto & it : defined_achievements) {
+ try {
+ std::string name = static_cast(it["name"]);
+ if (name.length() > 0) {
+ std::string normal = Local_Storage::get_game_settings_path() + static_cast(it["icon"]);
+ std::string gray = Local_Storage::get_game_settings_path() + static_cast(it["icongray"]);
+ if (normal.length() > 0 && gray.length() > 0) {
+ uint32 normal_height = 0;
+ uint32 normal_width = 0;
+ uint32 gray_height = 0;
+ uint32 gray_width = 0;
+ std::vector normal_pixels(local_storage->load_image(normal, &normal_width, &normal_height));
+ std::vector gray_pixels(local_storage->load_image(gray, &gray_width, &gray_height));
+ if (normal_width > 0 && normal_height > 0 &&
+ gray_width > 0 && gray_height > 0) {
+ std::string normalStr;
+ std::string grayStr;
+ normalStr.reserve(sizeof(uint32_t) * normal_width * normal_height);
+ grayStr.reserve(sizeof(uint32_t) * gray_width * gray_height);
+ for (auto & pix : normal_pixels) {
+ normalStr += pix.channels.r;
+ normalStr += pix.channels.g;
+ normalStr += pix.channels.b;
+ normalStr += pix.channels.a;
+ }
+ for (auto & pix : gray_pixels) {
+ grayStr += pix.channels.r;
+ grayStr += pix.channels.g;
+ grayStr += pix.channels.b;
+ grayStr += pix.channels.a;
+ }
+ achievement_image_data_normal[name] = settings->add_image(normalStr, normal_width, normal_height);
+ achievement_image_data_gray[name] = settings->add_image(grayStr, gray_width, gray_height);
+ count++;
+ }
+ }
+ }
+ } catch (...) {}
+ }
+
+ PRINT_DEBUG("loaded %llu achievement images.\n", count);
}
void load_achievements()
@@ -590,10 +656,18 @@ bool StoreStats()
int GetAchievementIcon( const char *pchName )
{
PRINT_DEBUG("GetAchievementIcon\n");
- if (pchName == nullptr) return 0;
+ int ret = 0;
+ if (pchName == nullptr) return ret;
std::lock_guard lock(global_mutex);
- return 0;
+ bool achieved = false;
+ if ((GetAchievementAndUnlockTime(pchName, &achieved, NULL) == true) && (achieved == true)) {
+ ret = achievement_image_data_normal_find(pchName);
+ } else {
+ ret = achievement_image_data_gray_find(pchName);
+ }
+
+ return ret;
}
From 2164ff292cd938528cd7ddf67cea6af3ad355b2c Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Fri, 15 Nov 2024 13:01:52 -0500
Subject: [PATCH 28/67] Extra debugging log functions.
---
overlay_experimental/Renderer_Detector.cpp | 2 +-
overlay_experimental/internal_includes.h | 5 +++++
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/overlay_experimental/Renderer_Detector.cpp b/overlay_experimental/Renderer_Detector.cpp
index 687b12f..7daa725 100644
--- a/overlay_experimental/Renderer_Detector.cpp
+++ b/overlay_experimental/Renderer_Detector.cpp
@@ -1401,7 +1401,7 @@ public:
}
stop_detection_cv.notify_all();
- SPDLOG_TRACE("Renderer detection done {}.", (void*)renderer_hook);
+ SPDLOG_TRACE("Renderer detection done %p.", (void*)renderer_hook);
return renderer_hook;
});
diff --git a/overlay_experimental/internal_includes.h b/overlay_experimental/internal_includes.h
index 16b3291..c764fa9 100644
--- a/overlay_experimental/internal_includes.h
+++ b/overlay_experimental/internal_includes.h
@@ -38,6 +38,8 @@
#include
#endif
+#define PRINT_DEBUG_NO_LINENUM(a, ...) do {FILE *t = fopen("STEAM_LOG.txt", "a"); fprintf(t, a, __VA_ARGS__); fclose(t);} while (0)
+
#ifndef SPDLOG_TRACE
#define SPDLOG_TRACE(x, ...) PRINT_DEBUG(x "\n", __VA_ARGS__)
#endif
@@ -47,6 +49,9 @@
#ifndef SPDLOG_INFO
#define SPDLOG_INFO(x, ...) PRINT_DEBUG(x "\n", __VA_ARGS__)
#endif
+#ifndef SPDLOG_INFO_NO_NEWLINE
+#define SPDLOG_INFO_NO_NEWLINE(x, ...) PRINT_DEBUG_NO_LINENUM(x, __VA_ARGS__)
+#endif
#ifndef SPDLOG_WARN
#define SPDLOG_WARN(x, ...) PRINT_DEBUG(x "\n", __VA_ARGS__)
#endif
From 77d2a84af8e8cdd7372e930c2c1ea8b0c071ffb6 Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Fri, 15 Nov 2024 13:14:39 -0500
Subject: [PATCH 29/67] Wine + Enscripten fixes for OpenGL_Hook.cpp.
---
overlay_experimental/windows/OpenGL_Hook.cpp | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/overlay_experimental/windows/OpenGL_Hook.cpp b/overlay_experimental/windows/OpenGL_Hook.cpp
index e88de9d..43e4050 100644
--- a/overlay_experimental/windows/OpenGL_Hook.cpp
+++ b/overlay_experimental/windows/OpenGL_Hook.cpp
@@ -163,12 +163,7 @@ std::weak_ptr OpenGL_Hook::CreateImageResource(const void* image_data,
{
GLuint* texture = new GLuint(0);
glGenTextures(1, texture);
- if (glGetError() != GL_NO_ERROR)
- {
- delete texture;
- return std::shared_ptr(nullptr);
- }
-
+
// Save old texture id
GLint oldTex;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTex);
@@ -177,13 +172,17 @@ std::weak_ptr OpenGL_Hook::CreateImageResource(const void* image_data,
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Upload pixels into texture
+#if defined(GL_UNPACK_ROW_LENGTH) && !defined(__EMSCRIPTEN__)
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+#endif
+
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data);
-
glBindTexture(GL_TEXTURE_2D, oldTex);
-
+ glFlush();
auto ptr = std::shared_ptr((uint64_t*)texture, [](uint64_t* handle)
{
if (handle != nullptr)
From 59b8354f2d1ed9c9e7399c057e86fc25dc37a602 Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Fri, 15 Nov 2024 13:19:02 -0500
Subject: [PATCH 30/67] Win7 / Wine fixes DX11_Hook.cpp.
Don't create image resources if the D3D device isn't inited yet.
(Causes app crash.)
Set quality value on substruct.
---
overlay_experimental/windows/DX11_Hook.cpp | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/overlay_experimental/windows/DX11_Hook.cpp b/overlay_experimental/windows/DX11_Hook.cpp
index 14111fe..9607dfd 100644
--- a/overlay_experimental/windows/DX11_Hook.cpp
+++ b/overlay_experimental/windows/DX11_Hook.cpp
@@ -207,6 +207,7 @@ DX11_Hook::DX11_Hook():
_Hooked(false),
_WindowsHooked(false),
pContext(nullptr),
+ pDevice(nullptr),
mainRenderTargetView(nullptr),
Present(nullptr),
ResizeBuffers(nullptr),
@@ -263,6 +264,11 @@ void DX11_Hook::LoadFunctions(
std::weak_ptr DX11_Hook::CreateImageResource(const void* image_data, uint32_t width, uint32_t height)
{
+ if (pDevice == nullptr) {
+ SPDLOG_INFO("DX11 CreateImageResource %p pDevice is NULL.\n", image_data);
+ return std::shared_ptr();
+ }
+
ID3D11ShaderResourceView** resource = new ID3D11ShaderResourceView*(nullptr);
// Create texture
@@ -273,6 +279,7 @@ std::weak_ptr DX11_Hook::CreateImageResource(const void* image_data, u
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
+ desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0;
@@ -282,6 +289,7 @@ std::weak_ptr DX11_Hook::CreateImageResource(const void* image_data, u
subResource.pSysMem = image_data;
subResource.SysMemPitch = desc.Width * 4;
subResource.SysMemSlicePitch = 0;
+
pDevice->CreateTexture2D(&desc, &subResource, &pTexture);
if (pTexture != nullptr)
From 5241fc892f6112ddc8b2fa82a8fd0d63a12c50e9 Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Fri, 15 Nov 2024 13:24:34 -0500
Subject: [PATCH 31/67] Overlay: Implement achievement icon display.
Display achievement icons in steam_overlay, and during achievement
notifications.
Add total achievement counts and progress bar to steam_overlay.
Add new global settings for displaying unearned hidden achievements in
the achievement list and displaying achievement descriptions in unlock
notifications. (Both disabled by default.)
---
dll/settings_parser.cpp | 52 ++++-
dll/settings_parser.h | 2 +-
overlay_experimental/steam_overlay.cpp | 281 ++++++++++++++++++++++---
overlay_experimental/steam_overlay.h | 15 +-
4 files changed, 316 insertions(+), 34 deletions(-)
diff --git a/dll/settings_parser.cpp b/dll/settings_parser.cpp
index 87ec1d7..03e094c 100644
--- a/dll/settings_parser.cpp
+++ b/dll/settings_parser.cpp
@@ -334,10 +334,25 @@ uint32 create_localstorage_settings(Settings **settings_client_out, Settings **s
bool disable_networking = false;
bool disable_overlay = false;
bool disable_lobby_creation = false;
+ bool enable_achievement_desc_on_unlock = false;
+ bool enable_displaying_hidden_achievements = false;
int build_id = 10;
bool warn_forced = false;
+ {
+ std::string steam_settings_path = local_storage->get_global_settings_path();
+
+ std::vector paths = local_storage->get_filenames_path(steam_settings_path);
+ for (auto & p: paths) {
+ if (p == "enable_achievement_desc_on_unlock.txt") {
+ enable_achievement_desc_on_unlock = true;
+ } else if (p == "enable_displaying_hidden_achievements.txt") {
+ enable_displaying_hidden_achievements = true;
+ }
+ }
+ }
+
{
std::string steam_settings_path = Local_Storage::get_game_settings_path();
@@ -352,6 +367,10 @@ uint32 create_localstorage_settings(Settings **settings_client_out, Settings **s
disable_overlay = true;
} else if (p == "disable_lobby_creation.txt") {
disable_lobby_creation = true;
+ } else if (p == "enable_achievement_desc_on_unlock.txt") {
+ enable_achievement_desc_on_unlock = true;
+ } else if (p == "enable_displaying_hidden_achievements.txt") {
+ enable_displaying_hidden_achievements = true;
} else if (p == "force_language.txt") {
int len = Local_Storage::get_file_data(steam_settings_path + "force_language.txt", language, sizeof(language) - 1);
if (len > 0) {
@@ -410,6 +429,10 @@ uint32 create_localstorage_settings(Settings **settings_client_out, Settings **s
settings_server->warn_local_save = local_save;
settings_client->supported_languages = supported_languages;
settings_server->supported_languages = supported_languages;
+ settings_client->set_show_achievement_desc_on_unlock(enable_achievement_desc_on_unlock);
+ settings_server->set_show_achievement_desc_on_unlock(enable_achievement_desc_on_unlock);
+ settings_client->set_show_achievement_hidden_unearned(enable_displaying_hidden_achievements);
+ settings_server->set_show_achievement_hidden_unearned(enable_displaying_hidden_achievements);
{
std::string dlc_config_path = Local_Storage::get_game_settings_path() + "DLC.txt";
@@ -666,8 +689,31 @@ uint32 create_localstorage_settings(Settings **settings_client_out, Settings **s
return appid;
}
-void save_global_settings(Local_Storage *local_storage, char *name, char *language)
+void save_global_settings(Local_Storage *local_storage, Settings * client_settings)
{
- local_storage->store_data_settings("account_name.txt", name, strlen(name));
- local_storage->store_data_settings("language.txt", language, strlen(language));
+ if ((local_storage != nullptr) && (client_settings != nullptr)) {
+ std::string name = client_settings->get_local_name();
+ std::string language = client_settings->get_language();
+
+ local_storage->store_data_settings("account_name.txt", (char*)name.c_str(), name.length());
+ local_storage->store_data_settings("language.txt", (char*)language.c_str(), language.length());
+ if (client_settings->get_show_achievement_desc_on_unlock()) {
+ if (local_storage->data_settings_exists("enable_achievement_desc_on_unlock.txt") != true) {
+ local_storage->store_data_settings("enable_achievement_desc_on_unlock.txt", " ", sizeof(" "));
+ }
+ } else {
+ if (local_storage->data_settings_exists("enable_achievement_desc_on_unlock.txt") == true) {
+ local_storage->delete_data_settings("enable_achievement_desc_on_unlock.txt");
+ }
+ }
+ if (client_settings->get_show_achievement_hidden_unearned()) {
+ if (local_storage->data_settings_exists("enable_displaying_hidden_achievements.txt") != true) {
+ local_storage->store_data_settings("enable_displaying_hidden_achievements.txt", " ", sizeof(" "));
+ }
+ } else {
+ if (local_storage->data_settings_exists("enable_displaying_hidden_achievements.txt") == true) {
+ local_storage->delete_data_settings("enable_displaying_hidden_achievements.txt");
+ }
+ }
+ }
}
diff --git a/dll/settings_parser.h b/dll/settings_parser.h
index 38b926c..cfa9f6c 100644
--- a/dll/settings_parser.h
+++ b/dll/settings_parser.h
@@ -22,6 +22,6 @@
//returns appid
uint32 create_localstorage_settings(Settings **settings_client_out, Settings **settings_server_out, Local_Storage **local_storage_out);
-void save_global_settings(Local_Storage *local_storage, char *name, char *language);
+void save_global_settings(Local_Storage *local_storage, Settings *client_settings);
#endif
diff --git a/overlay_experimental/steam_overlay.cpp b/overlay_experimental/steam_overlay.cpp
index a0205c2..c053ece 100644
--- a/overlay_experimental/steam_overlay.cpp
+++ b/overlay_experimental/steam_overlay.cpp
@@ -100,6 +100,85 @@ int find_free_notification_id(std::vector const& notifications)
#include "notification.h"
+void Steam_Overlay::LoadAchievementImage(Overlay_Achievement & ach)
+{
+ PRINT_DEBUG("LoadAchievementImage() %s.\n", ach.name.c_str());
+
+ // Image load.
+ Steam_Utils* steamUtils = get_steam_client()->steam_utils;
+ Steam_User_Stats* steamUserStats = get_steam_client()->steam_user_stats;
+ int32 image_handle = steamUserStats->GetAchievementIcon(ach.name.c_str());
+ if (image_handle != 0) {
+ uint32 width = 0;
+ uint32 height = 0;
+ if ((steamUtils->GetImageSize(image_handle, &width, &height) == true) &&
+ (width > 0) && (height > 0)) {
+
+ PRINT_DEBUG("LoadAchievementImage() %d %d %d.\n", image_handle, width, height);
+
+ if (ach.raw_image != NULL) {
+ delete ach.raw_image;
+ ach.raw_image = NULL;
+ ach.raw_image_width = 0;
+ ach.raw_image_height = 0;
+ }
+ DestroyAchievementImageResource(ach);
+
+ uint8 * raw_image = new uint8[(width * height * sizeof(uint32))];
+ if ((raw_image != NULL) &&
+ (steamUtils->GetImageRGBA(image_handle,
+ raw_image,
+ (width * height * sizeof(uint32))) == true)) {
+ PRINT_DEBUG("LoadAchievementImage() %d -> %p.\n", image_handle, raw_image);
+ ach.raw_image = raw_image;
+ ach.raw_image_width = width;
+ ach.raw_image_height = height;
+ } else {
+ delete ach.raw_image;
+ PRINT_DEBUG("Image for achievement %s could not get pixel data.\n", ach.name.c_str());
+ }
+ } else {
+ PRINT_DEBUG("Image for achievement %s has an invalid size.\n", ach.name.c_str());
+ }
+ } else {
+ PRINT_DEBUG("Image for achievement %s is not loaded.\n", ach.name.c_str());
+ }
+}
+
+void Steam_Overlay::CreateAchievementImageResource(Overlay_Achievement & ach)
+{
+ PRINT_DEBUG("CreateAchievementImageResource() %s. %d x %d -> %p\n", ach.name.c_str(), ach.raw_image_width, ach.raw_image_height, ach.raw_image);
+
+ if (_renderer) {
+ if (ach.raw_image != NULL && ach.raw_image_width > 0 && ach.raw_image_height > 0 && ach.image_resource.expired() == true) {
+ std::weak_ptr test;
+ test = _renderer->CreateImageResource(ach.raw_image,
+ ach.raw_image_width,
+ ach.raw_image_height);
+ ach.image_resource = test;
+ std::shared_ptr test2;
+ test2 = test.lock();
+ if (!test2) {
+ PRINT_DEBUG("CreateAchievementImageResource() Unable to create resource for %s.\n", ach.name.c_str());
+ } else {
+ PRINT_DEBUG("CreateAchievementImageResource() created resource for %s -> %PRIu64.\n", ach.name.c_str(), *test2);
+ }
+
+ } else {
+ PRINT_DEBUG("CreateAchievementImageResource() invalid raw data for %s.\n", ach.name.c_str());
+ }
+ }
+}
+
+void Steam_Overlay::DestroyAchievementImageResource(Overlay_Achievement & ach)
+{
+ PRINT_DEBUG("DestroyAchievementImageResource() %s.\n", ach.name.c_str());
+
+ if (_renderer && ach.image_resource.expired() == false) {
+ _renderer->ReleaseImageResource(ach.image_resource);
+ }
+}
+
void Steam_Overlay::steam_overlay_run_every_runcb(void* object)
{
Steam_Overlay* _this = reinterpret_cast(object);
@@ -129,10 +208,14 @@ Steam_Overlay::Steam_Overlay(Settings* settings, SteamCallResults* callback_resu
show_achievements(false),
show_settings(false),
_renderer(nullptr),
- fonts_atlas(nullptr)
+ fonts_atlas(nullptr),
+ earned_achievement_count(0)
{
strncpy(username_text, settings->get_local_name(), sizeof(username_text));
+ show_achievement_desc_on_unlock = settings->get_show_achievement_desc_on_unlock();
+ show_achievement_hidden_unearned = settings->get_show_achievement_hidden_unearned();
+
if (settings->warn_forced) {
this->disable_forced = true;
this->warning_forced = true;
@@ -167,6 +250,17 @@ Steam_Overlay::Steam_Overlay(Settings* settings, SteamCallResults* callback_resu
Steam_Overlay::~Steam_Overlay()
{
run_every_runcb->remove(&Steam_Overlay::steam_overlay_run_every_runcb, this);
+ if (achievements.size()) {
+ for (auto & x : achievements) {
+ if (x.raw_image != NULL) {
+ delete x.raw_image;
+ x.raw_image = NULL;
+ x.raw_image_width = 0;
+ x.raw_image_height = 0;
+ }
+ DestroyAchievementImageResource(x);
+ }
+ }
}
bool Steam_Overlay::Ready() const
@@ -422,8 +516,28 @@ void Steam_Overlay::AddAchievementNotification(nlohmann::json const& ach)
Notification notif;
notif.id = id;
notif.type = notification_type_achievement;
- // Load achievement image
- notif.message = ach["displayName"].get() + "\n" + ach["description"].get();
+ // Achievement image
+ if (achievements.size() > 0) {
+ for (auto & x : achievements) {
+ if (x.name == ach["name"].get()) {
+ // Reload the image due to the pop.
+ LoadAchievementImage(x);
+ DestroyAchievementImageResource(x);
+ // Cannot call CreateAchievementImageResource(x) here. OpenGL displays bad texture.
+ notif.ach_name = x.name;
+ }
+ }
+ }
+ // Achievement count.
+ if (total_achievement_count > earned_achievement_count) {
+ earned_achievement_count++;
+ }
+ notif.message = "Achievement Unlocked!\n";
+ if (show_achievement_desc_on_unlock) {
+ notif.message += ach["displayName"].get() + "\n" + ach["description"].get();
+ } else {
+ notif.message += "\n" + ach["displayName"].get();
+ }
notif.start_time = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch());
notifications.emplace_back(notif);
have_notifications = true;
@@ -636,46 +750,85 @@ void Steam_Overlay::BuildNotifications(int width, int height)
std::queue friend_actions_temp;
+ ImVec2 notification_rez(((Notification::width >= 1.0f) ? (width / Notification::width) : (width * Notification::width)),
+ ((Notification::height >= 1.0f) ? (height / Notification::height) : (height * Notification::height))); // calc notification screen size.
+
{
std::lock_guard lock(notifications_mutex);
for (auto it = notifications.begin(); it != notifications.end(); ++it, ++i)
{
auto elapsed_notif = now - it->start_time;
-
+ float alpha = 0;
+ ImGuiStyle currentStyle = ImGui::GetStyle();
if ( elapsed_notif < Notification::fade_in)
{
- float alpha = Notification::max_alpha * (elapsed_notif.count() / static_cast(Notification::fade_in.count()));
+ alpha = Notification::max_alpha * (elapsed_notif.count() / static_cast(Notification::fade_in.count()));
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, alpha));
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(Notification::r, Notification::g, Notification::b, alpha));
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(255, 255, 255, alpha*2));
}
else if ( elapsed_notif > Notification::fade_out_start)
{
- float alpha = Notification::max_alpha * ((Notification::show_time - elapsed_notif).count() / static_cast(Notification::fade_out.count()));
+ alpha = Notification::max_alpha * ((Notification::show_time - elapsed_notif).count() / static_cast(Notification::fade_out.count()));
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, alpha));
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(Notification::r, Notification::g, Notification::b, alpha));
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(255, 255, 255, alpha*2));
}
else
{
+ alpha = Notification::max_alpha;
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, Notification::max_alpha));
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(Notification::r, Notification::g, Notification::b, Notification::max_alpha));
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(255, 255, 255, Notification::max_alpha*2));
}
-
+
ImGui::SetNextWindowPos(ImVec2((float)width - width * Notification::width, Notification::height * font_size * i ));
ImGui::SetNextWindowSize(ImVec2( width * Notification::width, Notification::height * font_size ));
ImGui::Begin(std::to_string(it->id).c_str(), nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBringToFrontOnFocus |
ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoDecoration);
+ // Notification image.
+ ImVec4 image_color_multipler(1, 1, 1, (alpha*2)); // fade in / out.
+ ImVec2 image_offset(((notification_rez.x * 0.04f) + currentStyle.FramePadding.x), ((notification_rez.y * 0.04f) + currentStyle.FramePadding.y)); // calc border.
+ ImVec2 image_max_resolution((notification_rez.x - image_offset.x), (notification_rez.y - image_offset.y)); // calc total space for image.
+ if (image_max_resolution.x > image_max_resolution.y) { // fix image aspect ratio. (square)
+ image_max_resolution.x = image_max_resolution.x - (image_max_resolution.x - image_max_resolution.y);
+ } else {
+ image_max_resolution.y = image_max_resolution.y - (image_max_resolution.y - image_max_resolution.x);
+ }
+ ImVec2 text_offset(image_offset.x, image_offset.y);
+ ImGui::SetCursorPos(image_offset);
+
switch (it->type)
{
case notification_type_achievement:
+ for (auto &a : achievements) {
+ if (a.name == it->ach_name) {
+ CreateAchievementImageResource(a);
+ if ((a.image_resource.expired() == false) &&
+ (a.raw_image_width > 0) &&
+ (a.raw_image_height > 0)) {
+ ImVec2 image_scale(image_max_resolution.x * 0.4f,
+ image_max_resolution.y * 0.4f);
+
+ // Fix text offset.
+ text_offset.x = image_offset.x + currentStyle.ItemSpacing.x + image_scale.x;
+
+ std::shared_ptr s_ptr = a.image_resource.lock();
+ ImGui::Image((ImTextureID)(intptr_t)*s_ptr, image_scale, ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), image_color_multipler);
+ }
+ break;
+ }
+ }
+ ImGui::SetCursorPos(text_offset);
+ ImGui::PushTextWrapPos(0.0f);
ImGui::TextWrapped("%s", it->message.c_str());
+ ImGui::PopTextWrapPos();
break;
case notification_type_invite:
{
+ ImGui::SetCursorPos(text_offset);
ImGui::TextWrapped("%s", it->message.c_str());
if (ImGui::Button("Join"))
{
@@ -686,6 +839,7 @@ void Steam_Overlay::BuildNotifications(int width, int height)
}
break;
case notification_type_message:
+ ImGui::SetCursorPos(text_offset);
ImGui::TextWrapped("%s", it->message.c_str()); break;
}
@@ -771,6 +925,17 @@ void Steam_Overlay::CreateFonts()
reset_LastError();
}
+void Steam_Overlay::DestroyAchievementImageResources()
+{
+ for (auto & x : achievements) {
+ if (x.image_resource.expired()) {
+ DestroyAchievementImageResource(x);
+ }
+ }
+
+ return;
+}
+
// Try to make this function as short as possible or it might affect game's fps.
void Steam_Overlay::OverlayProc()
{
@@ -809,6 +974,10 @@ void Steam_Overlay::OverlayProc()
ImGui::LabelText("##label", "Renderer: %s", (_renderer == nullptr ? "Unknown" : _renderer->GetLibraryName().c_str()));
+ ImGui::Text("Achievements earned: %d / %d", earned_achievement_count, total_achievement_count);
+ ImGui::SameLine();
+ ImGui::ProgressBar((earned_achievement_count / total_achievement_count), ImVec2((io.DisplaySize.x * 0.20f),0));
+
ImGui::Spacing();
if (ImGui::Button("Show Achievements")) {
show_achievements = true;
@@ -854,28 +1023,66 @@ void Steam_Overlay::OverlayProc()
if (ImGui::Begin("Achievement Window", &show)) {
ImGui::Text("List of achievements");
ImGui::BeginChild("Achievements");
+ ImGuiStyle currentStyle = ImGui::GetStyle();
+ float window_x_offset = (ImGui::GetWindowWidth() > currentStyle.ScrollbarSize) ? (ImGui::GetWindowWidth() - currentStyle.ScrollbarSize) : 0;
for (auto & x : achievements) {
bool achieved = x.achieved;
bool hidden = x.hidden && !achieved;
- ImGui::Separator();
- ImGui::Text("%s", x.title.c_str());
- if (hidden) {
- ImGui::Text("hidden achievement");
- } else {
- ImGui::TextWrapped("%s", x.description.c_str());
- }
+ if (!hidden || show_achievement_hidden_unearned) {
- if (achieved) {
- char buffer[80] = {};
- time_t unlock_time = (time_t)x.unlock_time;
- std::strftime(buffer, 80, "%Y-%m-%d at %H:%M:%S", std::localtime(&unlock_time));
+ if (x.raw_image == NULL) {
+ LoadAchievementImage(x);
+ }
- ImGui::TextColored(ImVec4(0, 255, 0, 255), "achieved on %s", buffer);
- } else {
- ImGui::TextColored(ImVec4(255, 0, 0, 255), "not achieved");
+ if (x.image_resource.expired() == true) {
+ CreateAchievementImageResource(x);
+ }
+
+ ImGui::Separator();
+
+ // Anchor the image to the right side of the list.
+ ImVec2 target = ImGui::GetCursorPos();
+ target.x = window_x_offset;
+ if (target.x > (x.raw_image_width * 0.4f)) {
+ target.x = target.x - (x.raw_image_width * 0.4f);
+ } else {
+ target.x = 0;
+ }
+
+ ImGui::PushTextWrapPos(target.x);
+ ImGui::Text("%s", x.title.c_str());
+ if (hidden) {
+ ImGui::Text("Hidden Achievement");
+ } else {
+ ImGui::Text("%s", x.description.c_str());
+ }
+ ImGui::PopTextWrapPos();
+
+ if (achieved) {
+ char buffer[80] = {};
+ time_t unlock_time = (time_t)x.unlock_time;
+ std::strftime(buffer, 80, "%Y-%m-%d at %H:%M:%S", std::localtime(&unlock_time));
+
+ ImGui::TextColored(ImVec4(0, 255, 0, 255), "achieved on %s", buffer);
+ } else {
+ ImGui::TextColored(ImVec4(255, 0, 0, 255), "not achieved");
+ }
+
+ // Set cursor for image output.
+ if (target.x != 0) {
+ ImGui::SetCursorPos(target);
+ }
+
+ if ((x.image_resource.expired() == false) &&
+ (x.raw_image_width > 0) &&
+ (x.raw_image_height > 0)) {
+ std::shared_ptr s_ptr = x.image_resource.lock();
+ ImGui::Image((ImTextureID)(intptr_t)*s_ptr, ImVec2(x.raw_image_width * 0.4f, x.raw_image_height * 0.4f));
+ }
+
+ ImGui::Separator();
}
- ImGui::Separator();
}
ImGui::EndChild();
}
@@ -905,6 +1112,11 @@ void Steam_Overlay::OverlayProc()
ImGui::Separator();
+ ImGui::Checkbox("Show achievement descriptions on unlock", &show_achievement_desc_on_unlock);
+ ImGui::Checkbox("Show unearned hidden achievements", &show_achievement_hidden_unearned);
+
+ ImGui::Separator();
+
if (!disable_forced) {
ImGui::Text("You may have to restart the game for these to apply.");
if (ImGui::Button("Save")) {
@@ -1004,15 +1216,16 @@ void Steam_Overlay::RunCallbacks()
{
if (!achievements.size()) {
Steam_User_Stats* steamUserStats = get_steam_client()->steam_user_stats;
- uint32 achievements_num = steamUserStats->GetNumAchievements();
- if (achievements_num) {
+ total_achievement_count = steamUserStats->GetNumAchievements();
+ if (total_achievement_count) {
PRINT_DEBUG("POPULATE OVERLAY ACHIEVEMENTS\n");
- for (unsigned i = 0; i < achievements_num; ++i) {
+ for (unsigned i = 0; i < total_achievement_count; ++i) {
Overlay_Achievement ach;
ach.name = steamUserStats->GetAchievementName(i);
ach.title = steamUserStats->GetAchievementDisplayAttribute(ach.name.c_str(), "name");
ach.description = steamUserStats->GetAchievementDisplayAttribute(ach.name.c_str(), "desc");
const char *hidden = steamUserStats->GetAchievementDisplayAttribute(ach.name.c_str(), "hidden");
+
if (strlen(hidden) && hidden[0] == '1') {
ach.hidden = true;
} else {
@@ -1024,11 +1237,19 @@ void Steam_Overlay::RunCallbacks()
if (steamUserStats->GetAchievementAndUnlockTime(ach.name.c_str(), &achieved, &unlock_time)) {
ach.achieved = achieved;
ach.unlock_time = unlock_time;
+ if ((achieved == true) && (total_achievement_count > earned_achievement_count)) {
+ earned_achievement_count++;
+ }
} else {
ach.achieved = false;
ach.unlock_time = 0;
}
+ ach.raw_image = nullptr;
+ ach.raw_image_width = 0;
+ ach.raw_image_height = 0;
+ LoadAchievementImage(ach);
+
achievements.push_back(ach);
}
@@ -1062,7 +1283,7 @@ void Steam_Overlay::RunCallbacks()
data.m_bUserInitiated = true;
data.m_nAppID = settings->get_local_game_id().AppID();
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
-
+ DestroyAchievementImageResources(); // Don't recreate them here. OpenGL won't display them if we do.
overlay_state_changed = false;
}
@@ -1071,11 +1292,15 @@ void Steam_Overlay::RunCallbacks()
if (save_settings) {
char *language_text = valid_languages[current_language];
- save_global_settings(get_steam_client()->local_storage, username_text, language_text);
get_steam_client()->settings_client->set_local_name(username_text);
- get_steam_client()->settings_server->set_local_name(username_text);
get_steam_client()->settings_client->set_language(language_text);
+ get_steam_client()->settings_client->set_show_achievement_desc_on_unlock(show_achievement_desc_on_unlock);
+ get_steam_client()->settings_client->set_show_achievement_hidden_unearned(show_achievement_hidden_unearned);
+ get_steam_client()->settings_server->set_local_name(username_text);
get_steam_client()->settings_server->set_language(language_text);
+ get_steam_client()->settings_server->set_show_achievement_desc_on_unlock(show_achievement_desc_on_unlock);
+ get_steam_client()->settings_server->set_show_achievement_hidden_unearned(show_achievement_hidden_unearned);
+ save_global_settings(get_steam_client()->local_storage, get_steam_client()->settings_client);
steamFriends->resend_friend_data();
save_settings = false;
}
diff --git a/overlay_experimental/steam_overlay.h b/overlay_experimental/steam_overlay.h
index ca33e04..853c9c1 100644
--- a/overlay_experimental/steam_overlay.h
+++ b/overlay_experimental/steam_overlay.h
@@ -68,6 +68,7 @@ struct Notification
std::chrono::seconds start_time;
std::string message;
std::pair* frd;
+ std::string ach_name;
};
struct Overlay_Achievement
@@ -78,6 +79,10 @@ struct Overlay_Achievement
bool hidden;
bool achieved;
uint32 unlock_time;
+ uint8 * raw_image;
+ uint32 raw_image_width;
+ uint32 raw_image_height;
+ std::weak_ptr image_resource;
};
#ifdef EMU_OVERLAY
@@ -104,8 +109,8 @@ class Steam_Overlay
bool show_achievements, show_settings;
void *fonts_atlas;
- bool disable_forced, local_save, warning_forced;
- uint32_t appid;
+ bool disable_forced, local_save, warning_forced, show_achievement_desc_on_unlock, show_achievement_hidden_unearned;
+ uint32_t appid, total_achievement_count, earned_achievement_count;
char username_text[256];
std::atomic_bool save_settings;
@@ -149,6 +154,12 @@ class Steam_Overlay
void BuildFriendWindow(Friend const& frd, friend_window_state &state);
// Notifications like achievements, chat and invitations
void BuildNotifications(int width, int height);
+
+ void LoadAchievementImage(Overlay_Achievement & ach);
+ void CreateAchievementImageResource(Overlay_Achievement & ach);
+ void DestroyAchievementImageResource(Overlay_Achievement & ach);
+ void DestroyAchievementImageResources();
+
public:
Steam_Overlay(Settings* settings, SteamCallResults* callback_results, SteamCallBacks* callbacks, RunEveryRunCB* run_every_runcb, Networking *network);
From 1408890d208a6fbd0e86791a0c085a23c1e220cc Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Sat, 16 Nov 2024 22:26:08 -0500
Subject: [PATCH 32/67] Enumerate fonts under Windows instead of ...
... hardcoding a path to a font file from the system directory.
Wine doesn't have anything in there, and doing it this way allows
Wine to "just work" without using Winetricks.
---
overlay_experimental/steam_overlay.cpp | 288 ++++++++++++++++++++++++-
1 file changed, 283 insertions(+), 5 deletions(-)
diff --git a/overlay_experimental/steam_overlay.cpp b/overlay_experimental/steam_overlay.cpp
index c053ece..fcbbf47 100644
--- a/overlay_experimental/steam_overlay.cpp
+++ b/overlay_experimental/steam_overlay.cpp
@@ -863,6 +863,221 @@ void Steam_Overlay::BuildNotifications(int width, int height)
}
}
+#if defined(__WINDOWS__)
+struct cb_font_str
+{
+ float font_size;
+ ImFontConfig fontcfg;
+ ImFontAtlas * atlas;
+ ImFont * defaultFont;
+ HDC hDevice;
+ int foundBits;
+};
+
+static cb_font_str CBSTR;
+
+DWORD LoadWindowsFontFromMem_GetSize_Helper(const LOGFONT *lf, DWORD * type) {
+ DWORD ret = 0;
+
+ if (lf != NULL && type != NULL) {
+ ret = GetFontData(CBSTR.hDevice, 0x66637474, 0, NULL, 0);
+ if (ret != GDI_ERROR && ret > 4) {
+ *type = 0x66637474;
+ } else {
+ ret = GetFontData(CBSTR.hDevice, 0, 0, NULL, 0);
+ if (ret != GDI_ERROR && ret > 4) {
+ *type = 0x0;
+ } else {
+ *type = ~((DWORD)0);
+ }
+ }
+ PRINT_DEBUG("%s %s %d 0x%x\n", "LoadWindowsFontFromMem_GetSize_Helper Result for font", lf->lfFaceName, ret, *type);
+ }
+
+ return ret;
+}
+
+int LoadWindowsFontFromMem(const LOGFONT *lf)
+{
+ int ret = 0;
+ HFONT hFont = NULL;
+ HGDIOBJ oldFont = NULL;
+
+ if (lf != NULL) {
+ hFont = CreateFontIndirect(lf);
+ if (hFont != NULL) {
+ oldFont = SelectObject(CBSTR.hDevice, hFont);
+ uint8_t metsize = GetOutlineTextMetrics(CBSTR.hDevice, 0, NULL);
+ if (metsize > 0) {
+ OUTLINETEXTMETRIC * metric = (OUTLINETEXTMETRIC*)calloc(metsize, 1);
+ if (metric != NULL) {
+ if (GetOutlineTextMetrics(CBSTR.hDevice, metsize, metric) != 0) {
+ if ((metric->otmfsType & 0x1) == 0) {
+ DWORD type = 0;
+ DWORD fontDataSize = LoadWindowsFontFromMem_GetSize_Helper(lf, &type);
+ if (fontDataSize != GDI_ERROR && fontDataSize > 4 && type != ~((DWORD)0)) {
+ uint8_t * fontData = (uint8*)malloc(fontDataSize);
+ if (fontData != NULL) {
+ ImFont * font = NULL;
+ DWORD fontDataRet = GetFontData(CBSTR.hDevice, type, 0, fontData, fontDataSize);
+ if (fontDataRet != GDI_ERROR && fontDataRet == fontDataSize) {
+
+ if (memcmp("\0\0\0\0", fontData, sizeof("\0\0\0\0")) == 0) {
+ PRINT_DEBUG("%s\n", "Invalid font tag. Skipping.");
+ } else {
+
+ if (type == 0x66637474) {
+ if (memcmp(fontData, "ttcf", sizeof("ttcf")) != 0) {
+ PRINT_DEBUG("TAG %x %x %x %x %s\n", fontData[0], fontData[1], fontData[2], fontData[3], "NOT A TrueType Collection file, despite detection result.");
+ memset(fontData, '\0', fontDataSize);
+ free(fontData);
+ fontData = NULL;
+ } else {
+ PRINT_DEBUG("%s\n", "Found TrueType Collection file.");
+ }
+ }
+
+ if (fontData != NULL) {
+ PRINT_DEBUG("%s %s %s\n", "Font considered valid. Attempting to import", lf->lfFaceName, "into ImGUI.");
+ if ((CBSTR.foundBits & 0xF) != 0x0) {
+ CBSTR.fontcfg.MergeMode = true;
+ PRINT_DEBUG("%s\n", "Merging fonts.");
+ }
+
+ font = CBSTR.atlas->AddFontFromMemoryTTF(fontData, fontDataSize, CBSTR.font_size, &(CBSTR.fontcfg));
+ if (font != NULL) {
+ PRINT_DEBUG("%s %s %s\n", "ImGUI loaded font", lf->lfFaceName, "successfully.");
+ if (CBSTR.defaultFont == NULL) {
+ CBSTR.defaultFont = font;
+ }
+ ret = 1;
+ } else {
+ PRINT_DEBUG("%s %s.\n", "ImGUI failed to load font", lf->lfFaceName);
+ }
+ }
+
+ }
+
+ } else {
+ PRINT_DEBUG("%s %d.\n", "GetFontData() failed. Ret: ", fontDataRet);
+ }
+
+ if (font == NULL) {
+ if (fontData != NULL) {
+ memset(fontData, '\0', fontDataSize);
+ free(fontData);
+ fontData = NULL;
+ }
+ }
+ }
+ } else {
+ PRINT_DEBUG("%s %d.\n", "GetFontData() failed. Unable to get initial size of font data. Ret: ", fontDataSize);
+ }
+ } else {
+ PRINT_DEBUG("%s %s.\n", "Licensing failure. Cannot use font", lf->lfFaceName);
+ }
+ }
+
+ free(metric);
+ metric = NULL;
+ }
+ }
+ SelectObject(CBSTR.hDevice, oldFont);
+ DeleteObject(hFont);
+ }
+ }
+ return ret;
+}
+
+int CALLBACK cb_enumfonts(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD fontType, LPARAM UNUSED)
+{
+ int ret = 1; // Continue iteration.
+ cb_font_str * cbStr = &CBSTR;
+ if (CBSTR.atlas != NULL && lf != NULL && fontType == TRUETYPE_FONTTYPE) {
+ /*
+ foundBits:
+ Bit 1: Loaded ANSI font.
+ Bit 2: Loaded Japanese font.
+ Bit 4: Loaded Chinese font.
+ Bit 8: Loaded Korean font.
+ Bit 10: Loaded preferred ANSI font.
+ Bit 20: Loaded preferred CJ font.
+ Bit 40: Loaded preferred K font.
+ Bit 80: Searched for preferred fonts.
+ */
+ if ((CBSTR.foundBits & 0x80) == 0) {
+ // Load ANSI first, or the other fonts will define the glyphs for english text.
+ if ((CBSTR.foundBits & 0x1) == 0) {
+ // preferred ANSI font.
+ if ((strncmp(lf->lfFaceName, "Microsoft Sans Serif", sizeof("Microsoft Sans Serif")) == 0) && ((CBSTR.foundBits & 0x10) == 0)) {
+ if (LoadWindowsFontFromMem(lf) == 1) {
+ CBSTR.foundBits = CBSTR.foundBits | 0x10 | 0x1;
+ ret = 0;
+ PRINT_DEBUG("%s %s.\n", "Loaded preferred font:", lf->lfFaceName);
+ }
+ }
+ } else {
+ // preferred CJ font.
+ if ((strncmp(lf->lfFaceName, "SimSun", sizeof("SimSun")) == 0) && ((CBSTR.foundBits & 0x20) == 0)) {
+ if (LoadWindowsFontFromMem(lf) == 1) {
+ CBSTR.foundBits = CBSTR.foundBits | 0x20 | 0x2 | 0x4;
+ PRINT_DEBUG("%s %s.\n", "Loaded preferred font:", lf->lfFaceName);
+ }
+ }
+ // preferred K font.
+ if ((strncmp(lf->lfFaceName, "Malgun Gothic", sizeof("Malgun Gothic")) == 0) && ((CBSTR.foundBits & 0x40) == 0)) {
+ if (LoadWindowsFontFromMem(lf) == 1) {
+ CBSTR.foundBits = CBSTR.foundBits | 0x40 | 0x8;
+ PRINT_DEBUG("%s %s.\n", "Loaded preferred font:", lf->lfFaceName);
+ }
+ }
+ }
+ } else {
+ // Load ANSI first, or the other fonts will define the glyphs for english text.
+ if ((CBSTR.foundBits & 0x1) == 0) {
+ if (lf->lfCharSet == ANSI_CHARSET) {
+ if (LoadWindowsFontFromMem(lf) == 1) {
+ CBSTR.foundBits = CBSTR.foundBits | 0x1;
+ ret = 0;
+ PRINT_DEBUG("%s %s.\n", "Loaded ANSI_CHARSET:", lf->lfFaceName);
+ }
+ }
+ } else {
+ if ((CBSTR.foundBits & 0x2) == 0) {
+ if (lf->lfCharSet == SHIFTJIS_CHARSET) {
+ if (LoadWindowsFontFromMem(lf) == 1) {
+ CBSTR.foundBits = CBSTR.foundBits | 0x2;
+ PRINT_DEBUG("%s %s.\n", "Loaded SHIFTJIS_CHARSET:", lf->lfFaceName);
+ }
+ }
+ }
+ if ((CBSTR.foundBits & 0x4) == 0) {
+ if (lf->lfCharSet == CHINESEBIG5_CHARSET) {
+ if (LoadWindowsFontFromMem(lf) == 1) {
+ CBSTR.foundBits = CBSTR.foundBits | 0x4;
+ PRINT_DEBUG("%s %s.\n", "Loaded CHINESEBIG5_CHARSET:", lf->lfFaceName);
+ }
+ }
+ }
+ if ((CBSTR.foundBits & 0x8) == 0) {
+ if (lf->lfCharSet == HANGUL_CHARSET) {
+ if (LoadWindowsFontFromMem(lf) == 1) {
+ CBSTR.foundBits = CBSTR.foundBits | 0x8;
+ PRINT_DEBUG("%s %s.\n", "Loaded HANGUL_CHARSET:", lf->lfFaceName);
+ }
+ }
+ }
+ }
+ }
+ }
+ if ((CBSTR.foundBits & 0xF) == 0xF) {
+ PRINT_DEBUG("%s\n", "Loaded all needed fonts.");
+ ret = 0; // Stop iteration.
+ }
+ return ret;
+}
+#endif
+
void Steam_Overlay::CreateFonts()
{
if (fonts_atlas) return;
@@ -899,7 +1114,69 @@ void Steam_Overlay::CreateFonts()
ImFont *font = NULL;
#if defined(__WINDOWS__)
- font = Fonts->AddFontFromFileTTF("C:\\Windows\\Fonts\\micross.ttf", font_size, &fontcfg);
+ // Do this instead of calling Fonts->AddFontFromFileTTF(). As *some* Windows implementations don't ship anything in C:\Windows\Fonts.
+ HDC oDC = GetDC(NULL);
+ HWND oWND = WindowFromDC(oDC);
+ int caps = GetDeviceCaps(oDC, RASTERCAPS);
+ if (caps != 0) {
+
+ int width = GetDeviceCaps(oDC, HORZRES);
+ int height = GetDeviceCaps(oDC, VERTRES);
+ HBITMAP hBitmap = CreateCompatibleBitmap(oDC, width, height);
+
+ LOGFONT lf;
+ memset(&lf, '\0', sizeof(LOGFONT));
+ lf.lfCharSet = DEFAULT_CHARSET;
+ lf.lfHeight = font_size;
+ lf.lfQuality = ANTIALIASED_QUALITY;
+ memset(&CBSTR, '\0', sizeof(cb_font_str));
+ CBSTR.font_size = font_size;
+ CBSTR.fontcfg = fontcfg;
+ CBSTR.atlas = Fonts;
+ CBSTR.hDevice = CreateCompatibleDC(oDC);
+ HGDIOBJ hOldBitmap = SelectObject(CBSTR.hDevice, hBitmap);
+ DeleteObject(hOldBitmap);
+
+ PRINT_DEBUG("%s\n", "Atempting to load preferred ANSI font from Win32 API.");
+ EnumFontFamiliesExA(CBSTR.hDevice, &lf, cb_enumfonts, 0, 0);
+ if ((CBSTR.foundBits & 0x1) != 0x1) {
+ CBSTR.foundBits = CBSTR.foundBits | 0x80;
+ PRINT_DEBUG("%s\n", "Atempting to load generic ANSI font from Win32 API.");
+ EnumFontFamiliesExA(CBSTR.hDevice, &lf, cb_enumfonts, 0, 0);
+ if ((CBSTR.foundBits & 0x1) != 0x1) {
+ PRINT_DEBUG("%s\n", "Falling back to built in ImGUI ANSI font.");
+ CBSTR.defaultFont = Fonts->AddFontDefault(&fontcfg);
+ if (CBSTR.defaultFont == NULL) {
+ PRINT_DEBUG("%s\n", "Built in ImGUI ANSI font failed to load. Weird text will probably happen.");
+ }
+ CBSTR.foundBits = CBSTR.foundBits | 0x1;
+ }
+ CBSTR.foundBits = CBSTR.foundBits ^ 0x80;
+ }
+ if ((CBSTR.foundBits & 0xE) != 0xE) {
+ PRINT_DEBUG("%s\n", "Atempting to load preferred CJK fonts from Win32 API.");
+ EnumFontFamiliesExA(CBSTR.hDevice, &lf, cb_enumfonts, 0, 0);
+ }
+ CBSTR.foundBits = CBSTR.foundBits | 0x80;
+ if ((CBSTR.foundBits & 0xF) != 0xF) {
+ PRINT_DEBUG("%s\n", "Loading generic CJK fonts from Win32 API.");
+ EnumFontFamiliesExA(CBSTR.hDevice, &lf, cb_enumfonts, 0, 0);
+ }
+ if (CBSTR.defaultFont != NULL) {
+ font = CBSTR.defaultFont;
+ }
+ if (need_extra_fonts == true) {
+ if ((CBSTR.foundBits & 0xF) == 0xF) {
+ need_extra_fonts = false;
+ }
+ }
+
+ DeleteDC(CBSTR.hDevice); // Order is important.
+ DeleteObject(hBitmap);
+ }
+ ReleaseDC(oWND, oDC);
+#else
+ font = Fonts->AddFontFromFileTTF("/usr/share/fonts/truetype/roboto/unhinted/RobotoCondensed-Regular.ttf", font_size, &fontcfg);
#endif
if (!font) {
@@ -909,11 +1186,12 @@ void Steam_Overlay::CreateFonts()
font_notif = font_default = font;
if (need_extra_fonts) {
- PRINT_DEBUG("loading extra fonts\n");
- fontcfg.MergeMode = true;
#if defined(__WINDOWS__)
- Fonts->AddFontFromFileTTF("C:\\Windows\\Fonts\\simsun.ttc", font_size, &fontcfg);
- Fonts->AddFontFromFileTTF("C:\\Windows\\Fonts\\malgun.ttf", font_size, &fontcfg);
+ PRINT_DEBUG("%s\n", "Unable to load extra fonts! Some text may not be readable!");
+#else
+ PRINT_DEBUG("%s\n", "loading extra fonts.");
+ fontcfg.MergeMode = true;
+ Fonts->AddFontFromFileTTF("/usr/share/fonts/truetype/droid/DroidSansFallbackFull.ttf", font_size, &fontcfg);
#endif
}
From 0eaba52f76fc31d9598c574dac21bd0723497838 Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Mon, 25 Nov 2024 00:11:22 -0500
Subject: [PATCH 33/67] Make add_friend_avatars handle local_user avatar
... changes.
Implements STEAM_CALL_RESULT( AvatarImageLoaded_t ).
Adds support for a sending a STEAM_CALL_RESULT( PersonaStateChange_t ) with the k_EPersonaChangeAvatar flag.
Creates a mapping in Settings to hold the avatar image data.
Also adds additional debug logging to indicate which image handle is
returned for each user / image size.
---
dll/settings.cpp | 42 ++++++++++++++
dll/settings.h | 3 +
dll/steam_friends.h | 133 +++++++++++++++++++++++++++++++++++++++-----
3 files changed, 165 insertions(+), 13 deletions(-)
diff --git a/dll/settings.cpp b/dll/settings.cpp
index f347c0a..7d59938 100644
--- a/dll/settings.cpp
+++ b/dll/settings.cpp
@@ -224,3 +224,45 @@ int Settings::add_image(std::string data, uint32 width, uint32 height)
images[last] = dt;
return last;
}
+
+int Settings::get_profile_image(int eAvatarSize)
+{
+ int ret = 0;
+ for (auto i : profile_images) {
+ if (i.first == eAvatarSize) {
+ ret = i.second;
+ break;
+ }
+ }
+ return ret;
+}
+
+int Settings::set_profile_image(int eAvatarSize, Image_Data * image)
+{
+ bool size_ok = false;
+ int ref = 0;
+
+ if (image != NULL) {
+ if (eAvatarSize == k_EAvatarSize32x32 && image->width > 0 && image->width <= 32 && image->height > 0 && image->height <= 32)
+ size_ok = true;
+ if (eAvatarSize == k_EAvatarSize64x64 && image->width > 32 && image->width <= 64 && image->height > 32 && image->height <= 64)
+ size_ok = true;
+ if (eAvatarSize == k_EAvatarSize184x184 && image->width > 64 && image->width <= 184 && image->height > 64 && image->height <= 184)
+ size_ok = true;
+
+ if (size_ok == true && image->data.length() > 0) {
+ ref = this->add_image(image->data, image->width, image->height);
+ PRINT_DEBUG("set_profile_image %d -> %d.\n", eAvatarSize, ref);
+ profile_images[eAvatarSize] = ref;
+ } else {
+ PRINT_DEBUG("%s %d %dx%d %"PRI_ZU".\n",
+ "set_profile_image failed",
+ eAvatarSize,
+ image->width,
+ image->height,
+ image->data.length());
+ }
+ }
+
+ return ref;
+}
diff --git a/dll/settings.h b/dll/settings.h
index 8528895..202c68c 100644
--- a/dll/settings.h
+++ b/dll/settings.h
@@ -80,6 +80,7 @@ class Settings {
std::map app_paths;
std::map leaderboards;
std::map stats;
+ std::map profile_images;
bool create_unknown_leaderboards;
uint16 port;
@@ -147,6 +148,8 @@ public:
//images
std::map images;
int add_image(std::string data, uint32 width, uint32 height);
+ int get_profile_image(int eAvatarSize);
+ int set_profile_image(int eAvatarSize, Image_Data * image);
//controller
struct Controller_Settings controller_settings;
diff --git a/dll/steam_friends.h b/dll/steam_friends.h
index 5f28c95..7bce28e 100644
--- a/dll/steam_friends.h
+++ b/dll/steam_friends.h
@@ -94,25 +94,132 @@ bool isAppIdCompatible(Friend *f)
return settings->get_local_game_id().AppID() == f->appid();
}
+STEAM_CALL_RESULT( AvatarImageLoaded_t )
struct Avatar_Numbers add_friend_avatars(CSteamID id)
{
uint64 steam_id = id.ConvertToUint64();
auto avatar_ids = avatars.find(steam_id);
- if (avatar_ids != avatars.end()) {
- return avatar_ids->second;
+ bool generate = true;
+ int base_image = 0;
+ struct Avatar_Numbers avatar_numbers;
+ if (settings->get_local_steam_id().ConvertToUint64() == steam_id) {
+ avatar_numbers.smallest = settings->get_profile_image(k_EAvatarSize32x32);
+ if (avatar_numbers.smallest != 0) {
+ base_image = avatar_numbers.smallest;
+ }
+ avatar_numbers.medium = settings->get_profile_image(k_EAvatarSize64x64);
+ if (avatar_numbers.medium != 0) {
+ base_image = avatar_numbers.medium;
+ }
+ avatar_numbers.large = settings->get_profile_image(k_EAvatarSize184x184);
+ if (avatar_numbers.large != 0) {
+ base_image = avatar_numbers.large;
+ }
+
+ if (base_image != 0) {
+ generate = false;
+ if (avatar_numbers.smallest == 0) {
+ avatar_numbers.smallest = base_image;
+ }
+ if (avatar_numbers.medium == 0) {
+ avatar_numbers.medium = base_image;
+ }
+ if (avatar_numbers.large == 0) {
+ avatar_numbers.large = base_image;
+ }
+ }
+
+ if (avatar_ids != avatars.end()) {
+ // Check for updated entry.
+ if (avatar_numbers.smallest == avatar_ids->second.smallest &&
+ avatar_numbers.medium == avatar_ids->second.medium &&
+ avatar_numbers.large == avatar_ids->second.large) {
+ return avatar_ids->second;
+ }
+ }
+ } else {
+ //TODO: get real image data from other peers
+
+ if (avatar_ids != avatars.end()) {
+ //TODO: Check for updated entry.
+ return avatar_ids->second;
+ }
}
- //TODO: get real image data from self/other peers
- struct Avatar_Numbers avatar_numbers;
- std::string small_avatar(32 * 32 * 4, 0);
- std::string medium_avatar(64 * 64 * 4, 0);
- std::string large_avatar(184 * 184 * 4, 0);
+ if (generate == true) {
+ std::string small_avatar(32 * 32 * 4, 0);
+ std::string medium_avatar(64 * 64 * 4, 0);
+ std::string large_avatar(184 * 184 * 4, 0);
- avatar_numbers.smallest = settings->add_image(small_avatar, 32, 32);
- avatar_numbers.medium = settings->add_image(medium_avatar, 64, 64);
- avatar_numbers.large = settings->add_image(large_avatar, 184, 184);
+ avatar_numbers.smallest = settings->add_image(small_avatar, 32, 32);
+ avatar_numbers.medium = settings->add_image(medium_avatar, 64, 64);
+ avatar_numbers.large = settings->add_image(large_avatar, 184, 184);
+ }
avatars[steam_id] = avatar_numbers;
+
+ // Generate callbacks.
+ uint32 width = 0;
+ uint32 height = 0;
+ AvatarImageLoaded_t ail_data = {};
+ bool sent_ail = false;
+
+ auto image = settings->images.find(avatar_numbers.smallest);
+ if (image != settings->images.end()) {
+ width = image->second.width;
+ height = image->second.height;
+ } else {
+ width = 0;
+ height = 0;
+ }
+
+ if (avatar_numbers.smallest) {
+ ail_data.m_steamID = steam_id;
+ ail_data.m_iImage = avatar_numbers.smallest;
+ ail_data.m_iWide = width;
+ ail_data.m_iTall = height;
+ callback_results->addCallResult(ail_data.k_iCallback, &ail_data, sizeof(ail_data));
+ sent_ail = true;
+ }
+
+ image = settings->images.find(avatar_numbers.medium);
+ if (image != settings->images.end()) {
+ width = image->second.width;
+ height = image->second.height;
+ } else {
+ width = 0;
+ height = 0;
+ }
+
+ if (avatar_numbers.medium) {
+ ail_data.m_steamID = steam_id;
+ ail_data.m_iImage = avatar_numbers.medium;
+ ail_data.m_iWide = width;
+ ail_data.m_iTall = height;
+ callback_results->addCallResult(ail_data.k_iCallback, &ail_data, sizeof(ail_data));
+ sent_ail = true;
+ }
+
+ image = settings->images.find(avatar_numbers.large);
+ if (image != settings->images.end()) {
+ width = image->second.width;
+ height = image->second.height;
+ } else {
+ width = 0;
+ height = 0;
+ }
+
+ if (avatar_numbers.large) {
+ ail_data.m_steamID = steam_id;
+ ail_data.m_iImage = avatar_numbers.large;
+ ail_data.m_iWide = width;
+ ail_data.m_iTall = height;
+ callback_results->addCallResult(ail_data.k_iCallback, &ail_data, sizeof(ail_data));
+ sent_ail = true;
+ }
+ if (sent_ail) {
+ persona_change(id, k_EPersonaChangeAvatar);
+ }
return avatar_numbers;
}
@@ -594,10 +701,10 @@ void ActivateGameOverlayInviteDialog( CSteamID steamIDLobby )
// gets the small (32x32) avatar of the current user, which is a handle to be used in IClientUtils::GetImageRGBA(), or 0 if none set
int GetSmallFriendAvatar( CSteamID steamIDFriend )
{
- PRINT_DEBUG("Steam_Friends::GetSmallFriendAvatar\n");
//IMPORTANT NOTE: don't change friend avatar numbers for the same friend or else some games endlessly allocate stuff.
std::lock_guard lock(global_mutex);
struct Avatar_Numbers numbers = add_friend_avatars(steamIDFriend);
+ PRINT_DEBUG("Steam_Friends::GetSmallFriendAvatar%"PRIu64" %d.\n", steamIDFriend.ConvertToUint64(), numbers.smallest);
return numbers.smallest;
}
@@ -605,9 +712,9 @@ int GetSmallFriendAvatar( CSteamID steamIDFriend )
// gets the medium (64x64) avatar of the current user, which is a handle to be used in IClientUtils::GetImageRGBA(), or 0 if none set
int GetMediumFriendAvatar( CSteamID steamIDFriend )
{
- PRINT_DEBUG("Steam_Friends::GetMediumFriendAvatar\n");
std::lock_guard lock(global_mutex);
struct Avatar_Numbers numbers = add_friend_avatars(steamIDFriend);
+ PRINT_DEBUG("Steam_Friends::GetMediumFriendAvatar%"PRIu64" %d.\n", steamIDFriend.ConvertToUint64(), numbers.medium);
return numbers.medium;
}
@@ -616,9 +723,9 @@ int GetMediumFriendAvatar( CSteamID steamIDFriend )
// returns -1 if this image has yet to be loaded, in this case wait for a AvatarImageLoaded_t callback and then call this again
int GetLargeFriendAvatar( CSteamID steamIDFriend )
{
- PRINT_DEBUG("Steam_Friends::GetLargeFriendAvatar\n");
std::lock_guard lock(global_mutex);
struct Avatar_Numbers numbers = add_friend_avatars(steamIDFriend);
+ PRINT_DEBUG("Steam_Friends::GetLargeFriendAvatar %"PRIu64" %d.\n", steamIDFriend.ConvertToUint64(), numbers.large);
return numbers.large;
}
From d493e30b98947e51d95000059deb14c0563b295f Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Mon, 25 Nov 2024 00:50:40 -0500
Subject: [PATCH 34/67] Add avatar image loading from global ...
... settings directory.
Also adds some additional related debug logging, and a utility function
for converting between std::vector used by Local_Storage::load_image(),
and std::string used by Settings::add_image().
---
dll/local_storage.cpp | 17 +++++++++++++++++
dll/local_storage.h | 2 ++
dll/settings_parser.cpp | 35 +++++++++++++++++++++++++++++++++++
dll/steam_utils.h | 5 ++++-
4 files changed, 58 insertions(+), 1 deletion(-)
diff --git a/dll/local_storage.cpp b/dll/local_storage.cpp
index c8d1a33..597e0b4 100644
--- a/dll/local_storage.cpp
+++ b/dll/local_storage.cpp
@@ -34,6 +34,19 @@ struct File_Data {
std::string name;
};
+std::string convert_vector_image_pixel_t_to_std_string(std::vector & in) {
+ std::string out;
+
+ for (auto i : in) {
+ out += i.channels.r;
+ out += i.channels.g;
+ out += i.channels.b;
+ out += i.channels.a;
+ }
+
+ return out;
+}
+
#ifdef NO_DISK_WRITES
std::string Local_Storage::get_program_path()
{
@@ -807,6 +820,10 @@ std::vector Local_Storage::load_image(std::string const& image_pa
std::copy(img, img + width * height, res.begin());
stbi_image_free(img);
+ } else {
+ width = 0;
+ height = 0;
+ PRINT_DEBUG("%s %s. reason: %s\n", "Failed to load image at", image_path.c_str(), stbi_failure_reason());
}
if (out_width != nullptr) {
if (width > 0) {
diff --git a/dll/local_storage.h b/dll/local_storage.h
index ae7b6aa..7f8e6c9 100644
--- a/dll/local_storage.h
+++ b/dll/local_storage.h
@@ -41,6 +41,8 @@ struct image_t
std::vector pix_map;
};
+std::string convert_vector_image_pixel_t_to_std_string(std::vector & in);
+
class Local_Storage {
public:
static constexpr auto inventory_storage_folder = "inventory";
diff --git a/dll/settings_parser.cpp b/dll/settings_parser.cpp
index 03e094c..bb161a6 100644
--- a/dll/settings_parser.cpp
+++ b/dll/settings_parser.cpp
@@ -340,15 +340,32 @@ uint32 create_localstorage_settings(Settings **settings_client_out, Settings **s
bool warn_forced = false;
+ Image_Data profile_small;
+ Image_Data profile_medium;
+ Image_Data profile_large;
+
{
std::string steam_settings_path = local_storage->get_global_settings_path();
std::vector paths = local_storage->get_filenames_path(steam_settings_path);
for (auto & p: paths) {
+ PRINT_DEBUG("global settings path %s\n", p.c_str());
if (p == "enable_achievement_desc_on_unlock.txt") {
enable_achievement_desc_on_unlock = true;
} else if (p == "enable_displaying_hidden_achievements.txt") {
enable_displaying_hidden_achievements = true;
+ } else if (p == "profile_small.jpg") {
+ profile_small.data = convert_vector_image_pixel_t_to_std_string(local_storage->load_image(steam_settings_path + p, &profile_small.width, &profile_small.height));
+ } else if (p == "profile_medium.jpg") {
+ profile_medium.data = convert_vector_image_pixel_t_to_std_string(local_storage->load_image(steam_settings_path + p, &profile_medium.width, &profile_medium.height));
+ } else if (p == "profile_large.jpg") {
+ profile_large.data = convert_vector_image_pixel_t_to_std_string(local_storage->load_image(steam_settings_path + p, &profile_large.width, &profile_large.height));
+ } else if (p == "profile_small.png") {
+ profile_small.data = convert_vector_image_pixel_t_to_std_string(local_storage->load_image(steam_settings_path + p, &profile_small.width, &profile_small.height));
+ } else if (p == "profile_medium.png") {
+ profile_medium.data = convert_vector_image_pixel_t_to_std_string(local_storage->load_image(steam_settings_path + p, &profile_medium.width, &profile_medium.height));
+ } else if (p == "profile_large.png") {
+ profile_large.data = convert_vector_image_pixel_t_to_std_string(local_storage->load_image(steam_settings_path + p, &profile_large.width, &profile_large.height));
}
}
}
@@ -433,6 +450,24 @@ uint32 create_localstorage_settings(Settings **settings_client_out, Settings **s
settings_server->set_show_achievement_desc_on_unlock(enable_achievement_desc_on_unlock);
settings_client->set_show_achievement_hidden_unearned(enable_displaying_hidden_achievements);
settings_server->set_show_achievement_hidden_unearned(enable_displaying_hidden_achievements);
+ if (profile_small.data.length() > 0 && profile_small.width > 0 && profile_small.height > 0) {
+ settings_client->set_profile_image(k_EAvatarSize32x32, &profile_small);
+ settings_server->set_profile_image(k_EAvatarSize32x32, &profile_small);
+ } else {
+ PRINT_DEBUG("%s %"PRI_ZU" %d %d\n", "Small user profile image not defined.", profile_small.data.length(), profile_small.width, profile_small.height);
+ }
+ if (profile_medium.data.length() > 0 && profile_medium.width > 0 && profile_medium.height > 0) {
+ settings_client->set_profile_image(k_EAvatarSize64x64, &profile_medium);
+ settings_server->set_profile_image(k_EAvatarSize64x64, &profile_medium);
+ } else {
+ PRINT_DEBUG("%s %"PRI_ZU" %d %d\n", "Medium user profile image not defined.", profile_medium.data.length(), profile_medium.width, profile_medium.height);
+ }
+ if (profile_large.data.length() > 0 && profile_large.width > 0 && profile_large.height > 0) {
+ settings_client->set_profile_image(k_EAvatarSize184x184, &profile_large);
+ settings_server->set_profile_image(k_EAvatarSize184x184, &profile_large);
+ } else {
+ PRINT_DEBUG("%s %"PRI_ZU" %d %d\n", "Large user profile image not defined.", profile_large.data.length(), profile_large.width, profile_large.height);
+ }
{
std::string dlc_config_path = Local_Storage::get_game_settings_path() + "DLC.txt";
diff --git a/dll/steam_utils.h b/dll/steam_utils.h
index b473d54..9a0eb2c 100644
--- a/dll/steam_utils.h
+++ b/dll/steam_utils.h
@@ -116,7 +116,10 @@ bool GetImageRGBA( int iImage, uint8 *pubDest, int nDestBufferSize )
if (image == settings->images.end()) return false;
unsigned size = image->second.data.size();
- if (nDestBufferSize < size) size = nDestBufferSize;
+ if (nDestBufferSize < size) {
+ size = nDestBufferSize;
+ PRINT_DEBUG("GetImageRGBA %i Given buffer too small. Got 0x%x bytes. Need 0x%x bytes.", iImage, nDestBufferSize, size);
+ }
image->second.data.copy((char *)pubDest, nDestBufferSize);
return true;
}
From 1fa0f4d4d59dbe6a044a98204746f53c66b95f88 Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Mon, 25 Nov 2024 01:02:26 -0500
Subject: [PATCH 35/67] Add fs utility functions for overlay use.
As we need to add a file chooser to the overlay, we need the backend
functions for it to use.
This commit adds:
Local_Storage::get_parent_directory().
Local_Storage::is_directory().
Local_Storage::get_user_pictures_path().
Local_Storage::get_drive_list().
Posix version of DirectoryExists().
---
dll/local_storage.cpp | 122 ++++++++++++++++++++++++++++++++++++++++++
dll/local_storage.h | 4 ++
2 files changed, 126 insertions(+)
diff --git a/dll/local_storage.cpp b/dll/local_storage.cpp
index 597e0b4..9ed979c 100644
--- a/dll/local_storage.cpp
+++ b/dll/local_storage.cpp
@@ -53,12 +53,26 @@ std::string Local_Storage::get_program_path()
return " ";
}
+std::string Local_Storage::get_user_pictures_path()
+{
+ return " ";
+}
std::string Local_Storage::get_user_appdata_path()
{
return " ";
}
+bool Local_Storage::is_directory(std::string &path)
+{
+ return false;
+}
+
+std::string Local_Storage::get_parent_directory(std::string &path)
+{
+ return " ";
+}
+
std::string Local_Storage::get_game_settings_path()
{
return " ";
@@ -285,6 +299,29 @@ static std::vector get_filenames_recursive(std::string base_pa
#else
+static bool DirectoryExists(const char *path) {
+ char tmp[PATH_MAX_STRING_SIZE];
+ struct stat sb;
+ size_t len;
+
+ /* copy path */
+ len = strnlen (path, PATH_MAX_STRING_SIZE);
+ if (len == 0 || len == PATH_MAX_STRING_SIZE) {
+ return false;
+ }
+ memcpy (tmp, path, len);
+ tmp[len] = '\0';
+
+ /* check if path exists and is a directory */
+ if (stat (tmp, &sb) == 0) {
+ if (S_ISDIR (sb.st_mode)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
/* recursive mkdir */
static int mkdir_p(const char *dir, const mode_t mode) {
char tmp[PATH_MAX_STRING_SIZE];
@@ -423,6 +460,26 @@ std::string Local_Storage::get_game_settings_path()
return get_program_path().append(game_settings_folder).append(PATH_SEPARATOR);
}
+std::string Local_Storage::get_user_pictures_path() {
+ std::string user_pictures_path = "Pictures";
+#if defined(STEAM_WIN32)
+ WCHAR szPath[MAX_PATH] = {};
+
+ HRESULT hr = SHGetFolderPathW(NULL, CSIDL_MYPICTURES, NULL, 0, szPath);
+
+ if (SUCCEEDED(hr)) {
+ user_pictures_path = utf8_encode(szPath);
+ }
+
+#else
+ char *datadir = getenv("HOME");
+ if (datadir) {
+ user_pictures_path = datadir;
+ }
+#endif
+ return user_pictures_path;
+}
+
std::string Local_Storage::get_user_appdata_path()
{
std::string user_appdata_path = "SAVE";
@@ -505,6 +562,71 @@ Local_Storage::Local_Storage(std::string save_directory)
}
}
+std::string Local_Storage::get_parent_directory(std::string &path)
+{
+ std::string ret = "";
+ std::string temp = "";
+
+ ret = sanitize_file_name(path);
+ if (ret.length() > 1) {
+ temp = ret[(ret.length() - 1)];
+ if (temp == PATH_SEPARATOR) {
+ ret.erase((ret.length() - 1), 1);
+ }
+ }
+
+ if (ret.length() > 1) {
+ size_t last_pos = 0;
+ size_t count = 0;
+ for (auto i : ret) {
+ temp = i;
+ if (temp == PATH_SEPARATOR) {
+ last_pos = count;
+ }
+ count = count + 1;
+ }
+ if ((last_pos > 0) && (last_pos < (count - 1))) {
+ ret.erase(last_pos, (count - 1));
+ }
+ }
+
+ ret = desanitize_file_name(ret);
+
+ return ret;
+}
+
+bool Local_Storage::is_directory(std::string &path)
+{
+ bool ret = false;
+#if defined(STEAM_WIN32)
+ std::wstring strPath = utf8_decode(path);
+ ret = DirectoryExists(strPath.c_str());
+#else
+ ret = DirectoryExists(path.c_str());
+#endif
+ return ret;
+}
+
+std::vector Local_Storage::get_drive_list()
+{
+ std::vector ret;
+#if defined(STEAM_WIN32)
+ DWORD drives = GetLogicalDrives();
+ if (drives != 0) {
+ for (unsigned int x = 0; x < 26; x++) {
+ if (drives & (((DWORD)0x1) << x)) {
+ char tmp[2] = { 'A' + (char)x, '\0' };
+ ret.push_back(std::string(tmp) + ":");
+ }
+ }
+ }
+#else
+ //TODO: Parse /proc/self/mountinfo
+ ret.push_back("/");
+#endif
+ return ret;
+}
+
void Local_Storage::setAppId(uint32 appid)
{
this->appid = std::to_string(appid) + PATH_SEPARATOR;
diff --git a/dll/local_storage.h b/dll/local_storage.h
index 7f8e6c9..078a932 100644
--- a/dll/local_storage.h
+++ b/dll/local_storage.h
@@ -60,7 +60,11 @@ private:
public:
static std::string get_program_path();
static std::string get_game_settings_path();
+ static std::string get_user_pictures_path();
static std::string get_user_appdata_path();
+ static std::string get_parent_directory(std::string &path);
+ static std::vector get_drive_list();
+ static bool is_directory(std::string &path);
Local_Storage(std::string save_directory);
static int get_file_data(std::string full_path, char *data, unsigned int max_length, unsigned int offset=0);
void setAppId(uint32 appid);
From cde29f0fd077b27320518d7384e2b48964e311c4 Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Wed, 11 Dec 2024 16:52:51 -0500
Subject: [PATCH 36/67] Create GOLDBERG_CALLBACK_INTERNAL() macro.
This allows the usage of steam callbacks within the emulator itself.
---
dll/dll.h | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 66 insertions(+)
diff --git a/dll/dll.h b/dll/dll.h
index 1b34715..7e2effd 100644
--- a/dll/dll.h
+++ b/dll/dll.h
@@ -25,6 +25,72 @@
#define STEAMCLIENT_API static
#endif
+#define GOLDBERG_CALLBACK_INTERNAL(parent, fname, cb_type) \
+ struct GB_CCallbackInternal_ ## fname : private GB_CCallbackInterImp< sizeof(cb_type) > { \
+ public: \
+ ~GB_CCallbackInternal_ ## fname () { if (m_nCallbackFlags & k_ECallbackFlagsRegistered) { \
+ bool ready = false; \
+ do { \
+ if (global_mutex.try_lock() == true) { \
+ Steam_Client * client = get_steam_client(); \
+ if (client != NULL) { \
+ get_steam_client()->UnregisterCallback(this); \
+ ready = true; \
+ } \
+ global_mutex.unlock(); \
+ } \
+ } while (!ready); \
+ } }\
+ GB_CCallbackInternal_ ## fname () {} \
+ GB_CCallbackInternal_ ## fname ( const GB_CCallbackInternal_ ## fname & ) {} \
+ GB_CCallbackInternal_ ## fname & operator=(const GB_CCallbackInternal_ ## fname &) { return *this; } \
+ private: \
+ virtual void Run(void *callback) { \
+ if (!(m_nCallbackFlags & k_ECallbackFlagsRegistered)) { \
+ bool ready = false; \
+ do { \
+ if (global_mutex.try_lock() == true) { \
+ Steam_Client * client = get_steam_client(); \
+ if (client != NULL) { \
+ client->RegisterCallback(this, cb_type::k_iCallback); \
+ ready = true; \
+ } \
+ global_mutex.unlock(); \
+ } \
+ } while (!ready); \
+ } \
+ if (m_nCallbackFlags & k_ECallbackFlagsRegistered) { \
+ parent *obj = reinterpret_cast(reinterpret_cast(this) - offsetof(parent, m_steamcallback_ ## fname)); \
+ obj->fname(reinterpret_cast(callback)); \
+ } \
+ } \
+ } m_steamcallback_ ## fname ; void fname( cb_type *callback )
+
+template
+class GB_CCallbackInterImp : protected CCallbackBase
+{
+ public:
+ virtual ~GB_CCallbackInterImp() { if (m_nCallbackFlags & k_ECallbackFlagsRegistered) {
+ bool ready = false;
+ do {
+ if (global_mutex.try_lock() == true) {
+ Steam_Client * client = get_steam_client();
+ if (client != NULL) {
+ get_steam_client()->UnregisterCallback(this);
+ ready = true;
+ }
+ global_mutex.unlock();
+ }
+ } while (!ready);
+ } }
+ void SetGameserverFlag() { m_nCallbackFlags |= k_ECallbackFlagsGameServer; }
+ protected:
+ friend class CCallbackMgr;
+ virtual void Run(void *callback) = 0;
+ virtual void Run( void *callback, bool io_failure, SteamAPICall_t api_fp) { Run(callback); }
+ virtual int GetCallbackSizeBytes() { return sizeof_cb_type; }
+};
+
Steam_Client *get_steam_client();
bool steamclient_has_ipv6_functions();
From 75035de2f4ac24adac97f31dc648a7845421f84e Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Wed, 11 Dec 2024 16:58:36 -0500
Subject: [PATCH 37/67] Add try_get_steam_client().
This allows the emulator to attempt to access the global steam_client object
without creating it if it doesn't exist.
---
dll/dll.cpp | 10 ++++++++++
dll/dll.h | 1 +
2 files changed, 11 insertions(+)
diff --git a/dll/dll.cpp b/dll/dll.cpp
index 4fef715..7029d37 100644
--- a/dll/dll.cpp
+++ b/dll/dll.cpp
@@ -140,6 +140,16 @@ Steam_Client *get_steam_client()
return steamclient_instance;
}
+Steam_Client *try_get_steam_client()
+{
+ Steam_Client * ret = NULL;
+ if (global_mutex.try_lock() == true) {
+ ret = steamclient_instance;
+ global_mutex.unlock();
+ }
+ return ret;
+}
+
void destroy_client()
{
std::lock_guard lock(global_mutex);
diff --git a/dll/dll.h b/dll/dll.h
index 7e2effd..1cfdbb0 100644
--- a/dll/dll.h
+++ b/dll/dll.h
@@ -93,6 +93,7 @@ class GB_CCallbackInterImp : protected CCallbackBase
Steam_Client *get_steam_client();
bool steamclient_has_ipv6_functions();
+Steam_Client *try_get_steam_client();
HSteamUser flat_hsteamuser();
HSteamPipe flat_hsteampipe();
From f560fce352c4faa1a4d3497cbea7227c1df2c016 Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Wed, 11 Dec 2024 17:00:20 -0500
Subject: [PATCH 38/67] Add protobuf message type Image and Friend_Avatar.
Also adds Friend_Avatar to the Common_Message list of possible
messages.
---
dll/common_includes.h | 5 ++++-
dll/net.proto | 26 ++++++++++++++++++++++++++
dll/network.cpp | 5 +++++
dll/network.h | 1 +
4 files changed, 36 insertions(+), 1 deletion(-)
diff --git a/dll/common_includes.h b/dll/common_includes.h
index cf3e4c7..bf612c4 100644
--- a/dll/common_includes.h
+++ b/dll/common_includes.h
@@ -125,6 +125,7 @@ inline void reset_LastError()
#include
#include
#include
+ #include
#include
#include
@@ -220,4 +221,6 @@ inline std::string ascii_to_lowercase(std::string data) {
#define LOBBY_CONNECT_APPID ((uint32)-2)
-#endif//__INCLUDED_COMMON_INCLUDES__
+#define FRIEND_AVATAR_MAX_IMAGE_LENGTH (5 * 1024 * 1024)
+
+#endif//__INCLUDED_COMMON_INCLUDES__
\ No newline at end of file
diff --git a/dll/net.proto b/dll/net.proto
index 32e7852..cc1318f 100644
--- a/dll/net.proto
+++ b/dll/net.proto
@@ -179,6 +179,31 @@ message Friend {
uint64 lobby_id = 5;
}
+message Image {
+ enum MessageTypes {
+ REQUEST = 0;
+ NOTIFY = 1;
+ }
+
+ enum ImgTypes {
+ RAW = 0;
+ JPG = 1;
+ PNG = 2;
+ GIF = 3;
+ }
+
+ MessageTypes type = 1;
+ ImgTypes img_type = 2;
+ uint32 img_width = 3;
+ uint32 img_height = 4;
+ uint32 img_components = 5;
+ bytes img_data = 6;
+}
+
+message Friend_Avatar {
+ Image img = 1;
+}
+
message Auth_Ticket {
uint32 number = 1;
@@ -230,6 +255,7 @@ message Common_Message {
Networking_Sockets networking_sockets = 13;
Steam_Messages steam_messages = 14;
Networking_Messages networking_messages = 15;
+ Friend_Avatar friend_avatar = 16;
}
uint32 source_ip = 128;
diff --git a/dll/network.cpp b/dll/network.cpp
index 4f0d026..370e279 100644
--- a/dll/network.cpp
+++ b/dll/network.cpp
@@ -581,6 +581,11 @@ void Networking::do_callbacks_message(Common_Message *msg)
PRINT_DEBUG("has_networking_messages\n");
run_callbacks(CALLBACK_ID_NETWORKING_MESSAGES, msg);
}
+
+ if (msg->has_friend_avatar()) {
+ PRINT_DEBUG("has_friend_avatar\n");
+ run_callbacks(CALLBACK_ID_FRIEND_AVATAR, msg);
+ }
}
bool Networking::handle_tcp(Common_Message *msg, struct TCP_Socket &socket)
diff --git a/dll/network.h b/dll/network.h
index 72e9f39..8baaab7 100644
--- a/dll/network.h
+++ b/dll/network.h
@@ -61,6 +61,7 @@ enum Callback_Ids {
CALLBACK_ID_NETWORKING_SOCKETS,
CALLBACK_ID_STEAM_MESSAGES,
CALLBACK_ID_NETWORKING_MESSAGES,
+ CALLBACK_ID_FRIEND_AVATAR,
CALLBACK_IDS_MAX
};
From bfb027230041ee330b22fc907d83e388e5832e0c Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Wed, 11 Dec 2024 17:09:06 -0500
Subject: [PATCH 39/67] Fix debug message for Steam_Utils::GetImageRGBA().
---
dll/steam_utils.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dll/steam_utils.h b/dll/steam_utils.h
index 9a0eb2c..b65b554 100644
--- a/dll/steam_utils.h
+++ b/dll/steam_utils.h
@@ -117,8 +117,8 @@ bool GetImageRGBA( int iImage, uint8 *pubDest, int nDestBufferSize )
unsigned size = image->second.data.size();
if (nDestBufferSize < size) {
+ PRINT_DEBUG("GetImageRGBA %i Given buffer too small. Got 0x%x bytes. Need 0x%x bytes.\n", iImage, nDestBufferSize, size);
size = nDestBufferSize;
- PRINT_DEBUG("GetImageRGBA %i Given buffer too small. Got 0x%x bytes. Need 0x%x bytes.", iImage, nDestBufferSize, size);
}
image->second.data.copy((char *)pubDest, nDestBufferSize);
return true;
From 55277ab77089cd52adc0d22c9e4983dbed01f45c Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Wed, 11 Dec 2024 17:13:21 -0500
Subject: [PATCH 40/67] Change filenames for global settings avatar images...
... and fix the debug messages.
This changes the filenames to be "avatar_*" instead of "profile_*" to
keep things consistent with the proper naming elsewhere.
---
dll/settings_parser.cpp | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/dll/settings_parser.cpp b/dll/settings_parser.cpp
index bb161a6..c75743f 100644
--- a/dll/settings_parser.cpp
+++ b/dll/settings_parser.cpp
@@ -354,17 +354,17 @@ uint32 create_localstorage_settings(Settings **settings_client_out, Settings **s
enable_achievement_desc_on_unlock = true;
} else if (p == "enable_displaying_hidden_achievements.txt") {
enable_displaying_hidden_achievements = true;
- } else if (p == "profile_small.jpg") {
+ } else if (p == "avatar_small.jpg") {
profile_small.data = convert_vector_image_pixel_t_to_std_string(local_storage->load_image(steam_settings_path + p, &profile_small.width, &profile_small.height));
- } else if (p == "profile_medium.jpg") {
+ } else if (p == "avatar_medium.jpg") {
profile_medium.data = convert_vector_image_pixel_t_to_std_string(local_storage->load_image(steam_settings_path + p, &profile_medium.width, &profile_medium.height));
- } else if (p == "profile_large.jpg") {
+ } else if (p == "avatar_large.jpg") {
profile_large.data = convert_vector_image_pixel_t_to_std_string(local_storage->load_image(steam_settings_path + p, &profile_large.width, &profile_large.height));
- } else if (p == "profile_small.png") {
+ } else if (p == "avatar_small.png") {
profile_small.data = convert_vector_image_pixel_t_to_std_string(local_storage->load_image(steam_settings_path + p, &profile_small.width, &profile_small.height));
- } else if (p == "profile_medium.png") {
+ } else if (p == "avatar_medium.png") {
profile_medium.data = convert_vector_image_pixel_t_to_std_string(local_storage->load_image(steam_settings_path + p, &profile_medium.width, &profile_medium.height));
- } else if (p == "profile_large.png") {
+ } else if (p == "avatar_large.png") {
profile_large.data = convert_vector_image_pixel_t_to_std_string(local_storage->load_image(steam_settings_path + p, &profile_large.width, &profile_large.height));
}
}
@@ -454,19 +454,19 @@ uint32 create_localstorage_settings(Settings **settings_client_out, Settings **s
settings_client->set_profile_image(k_EAvatarSize32x32, &profile_small);
settings_server->set_profile_image(k_EAvatarSize32x32, &profile_small);
} else {
- PRINT_DEBUG("%s %"PRI_ZU" %d %d\n", "Small user profile image not defined.", profile_small.data.length(), profile_small.width, profile_small.height);
+ PRINT_DEBUG("%s %"PRI_ZU" %d %d\n", "Small user avatar image not defined.", profile_small.data.length(), profile_small.width, profile_small.height);
}
if (profile_medium.data.length() > 0 && profile_medium.width > 0 && profile_medium.height > 0) {
settings_client->set_profile_image(k_EAvatarSize64x64, &profile_medium);
settings_server->set_profile_image(k_EAvatarSize64x64, &profile_medium);
} else {
- PRINT_DEBUG("%s %"PRI_ZU" %d %d\n", "Medium user profile image not defined.", profile_medium.data.length(), profile_medium.width, profile_medium.height);
+ PRINT_DEBUG("%s %"PRI_ZU" %d %d\n", "Medium user avatar image not defined.", profile_medium.data.length(), profile_medium.width, profile_medium.height);
}
if (profile_large.data.length() > 0 && profile_large.width > 0 && profile_large.height > 0) {
settings_client->set_profile_image(k_EAvatarSize184x184, &profile_large);
settings_server->set_profile_image(k_EAvatarSize184x184, &profile_large);
} else {
- PRINT_DEBUG("%s %"PRI_ZU" %d %d\n", "Large user profile image not defined.", profile_large.data.length(), profile_large.width, profile_large.height);
+ PRINT_DEBUG("%s %"PRI_ZU" %d %d\n", "Large user avatar image not defined.", profile_large.data.length(), profile_large.width, profile_large.height);
}
{
From e555bcef7aa2579ad97bf1f8272b64f9c8c14e4c Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Sat, 14 Dec 2024 19:48:59 -0500
Subject: [PATCH 41/67] Init callback objects first, fix mutex locking
Init callback related objects in Steam_Client before initing anything
else.
Fix missing global_mutex lock in Steam_Client::RegisterCallback() and
Steam_Client::UnregisterCallback().
---
dll/steam_client.cpp | 31 ++++++++++++++++++++++++-------
1 file changed, 24 insertions(+), 7 deletions(-)
diff --git a/dll/steam_client.cpp b/dll/steam_client.cpp
index 101d089..37c2365 100644
--- a/dll/steam_client.cpp
+++ b/dll/steam_client.cpp
@@ -50,16 +50,16 @@ static void background_thread(Steam_Client *client)
Steam_Client::Steam_Client()
{
- uint32 appid = create_localstorage_settings(&settings_client, &settings_server, &local_storage);
-
- network = new Networking(settings_server->get_local_steam_id(), appid, settings_server->get_port(), &(settings_server->custom_broadcasts), settings_server->disable_networking);
-
callback_results_client = new SteamCallResults();
callback_results_server = new SteamCallResults();
callbacks_client = new SteamCallBacks(callback_results_client);
callbacks_server = new SteamCallBacks(callback_results_server);
run_every_runcb = new RunEveryRunCB();
+ uint32 appid = create_localstorage_settings(&settings_client, &settings_server, &local_storage);
+
+ network = new Networking(settings_server->get_local_steam_id(), appid, settings_server->get_port(), &(settings_server->custom_broadcasts), settings_server->disable_networking);
+
PRINT_DEBUG("steam client init: id: %llu server id: %llu appid: %u port: %u \n", settings_client->get_local_steam_id().ConvertToUint64(), settings_server->get_local_steam_id().ConvertToUint64(), appid, settings_server->get_port());
if (appid) {
@@ -1433,9 +1433,22 @@ void Steam_Client::RegisterCallback( class CCallbackBase *pCallback, int iCallba
PRINT_DEBUG("Unknown callback base %i\n", base_callback);
};
+ std::lock_guard lock(global_mutex);
if (isGameServer) {
+ if (callback_results_server == nullptr) {
+ callback_results_server = new SteamCallResults();
+ }
+ if (callbacks_server == nullptr) {
+ callbacks_server = new SteamCallBacks(callback_results_server);
+ }
callbacks_server->addCallBack(iCallback, pCallback);
} else {
+ if (callback_results_client == nullptr) {
+ callback_results_client = new SteamCallResults();
+ }
+ if (callbacks_client == nullptr) {
+ callbacks_client = new SteamCallBacks(callback_results_client);
+ }
callbacks_client->addCallBack(iCallback, pCallback);
}
}
@@ -1657,10 +1670,15 @@ void Steam_Client::UnregisterCallback( class CCallbackBase *pCallback)
PRINT_DEBUG("Unknown callback base %i\n", base_callback);
};
+ std::lock_guard lock(global_mutex);
if (isGameServer) {
- callbacks_server->rmCallBack(iCallback, pCallback);
+ if (callbacks_server != nullptr) {
+ callbacks_server->rmCallBack(iCallback, pCallback);
+ }
} else {
- callbacks_client->rmCallBack(iCallback, pCallback);
+ if (callbacks_client != nullptr) {
+ callbacks_client->rmCallBack(iCallback, pCallback);
+ }
}
}
@@ -1670,7 +1688,6 @@ void Steam_Client::RegisterCallResult( class CCallbackBase *pCallback, SteamAPIC
std::lock_guard lock(global_mutex);
callback_results_client->addCallBack(hAPICall, pCallback);
callback_results_server->addCallBack(hAPICall, pCallback);
-
}
void Steam_Client::UnregisterCallResult( class CCallbackBase *pCallback, SteamAPICall_t hAPICall)
From 35ff20ebfc6c5eb3b3bd97b32d42b71ae2e2f924 Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Sat, 14 Dec 2024 19:57:04 -0500
Subject: [PATCH 42/67] Add image buffer writing, file copy, avatar save.
Adds functions for saving the user selected avatar image to the global
settings folder. (These also get reused to send the avatar to remote
users.)
---
dll/local_storage.cpp | 232 ++++++++++++++++++++++++++++++++++++++++++
dll/local_storage.h | 7 ++
2 files changed, 239 insertions(+)
diff --git a/dll/local_storage.cpp b/dll/local_storage.cpp
index 9ed979c..2d7d09d 100644
--- a/dll/local_storage.cpp
+++ b/dll/local_storage.cpp
@@ -47,6 +47,141 @@ std::string convert_vector_image_pixel_t_to_std_string(std::vectortarget != NULL &&
+ con->target_length > 0 &&
+ con->current_offset < con->target_length &&
+ (con->current_offset + size) < con->target_length) {
+ for (size_t x = 0; (x < size && (con->current_offset + x) < con->target_length); x++) {
+ con->target[(con->current_offset + x)] = in_data[x];
+ }
+ con->current_offset += size;
+ }
+ return;
+}
+
+std::string convert_raw_uint8_to_png_std_string(uint8 * in, int width, int height, int components) {
+ struct our_stbi_buffer buf;
+ std::string out;
+ out.clear();
+
+ if (in != NULL && width > 0 && height > 0 && components > 0 && components <= 4) {
+ buf.target_length = (width * height * components);
+ buf.current_offset = 0;
+ buf.target = new uint8[(width * height * components)];
+ if (buf.target != NULL) {
+ if (stbi_write_png_to_func(our_stbi_write_func, &buf, width, height, components, in, 0) == 1) {
+ for (size_t x = 0; x < (width * height * components); x++) {
+ char a = (char)buf.target[x];
+ out += a;
+ }
+ }
+
+ delete buf.target;
+ buf.target = NULL;
+ }
+ buf.target_length = 0;
+ buf.current_offset = 0;
+ }
+
+ return out;
+}
+
+std::string convert_raw_uint8_to_jpg_std_string(uint8 * in, int width, int height, int components) {
+ struct our_stbi_buffer buf;
+ std::string out;
+ out.clear();
+
+ if (in != NULL && width > 0 && height > 0 && components > 0 && components <= 4) {
+ buf.target_length = (width * height * components);
+ buf.current_offset = 0;
+ buf.target = new uint8[(width * height * components)];
+ if (buf.target != NULL) {
+ if (stbi_write_jpg_to_func(our_stbi_write_func, &buf, width, height, components, in, 0) == 1) {
+ for (size_t x = 0; x < (width * height * components); x++) {
+ char a = (char)buf.target[x];
+ out += a;
+ }
+ }
+
+ delete buf.target;
+ buf.target = NULL;
+ }
+ buf.target_length = 0;
+ buf.current_offset = 0;
+ }
+
+ return out;
+}
+
+std::string convert_imgbuf_std_string_to_std_string_uint8(std::string in,
+ int * out_width,
+ int * out_height,
+ int * out_components,
+ int desired_components) {
+ std::string out;
+ out.clear();
+ int w = 0;
+ int h = 0;
+ int c = 0;
+
+ if (in.length() > 0 &&
+ desired_components > 0 &&
+ desired_components <= 4) {
+ uint8 * buf = (uint8*)stbi_load_from_memory((stbi_uc *)in.c_str(), in.length(), &w, &h, &c, desired_components);
+ if (buf != NULL) {
+ if (w > 0 && h > 0 && desired_components > 0) {
+ for (size_t x = 0; x < (w * h * desired_components); x++) {
+ char a = buf[x];
+ out += a;
+ }
+ }
+ if (out_width != NULL) {
+ *out_width = w;
+ }
+ if (out_height != NULL) {
+ *out_height = h;
+ }
+ if (out_components != NULL) {
+ *out_components = c;
+ }
+ stbi_image_free(buf);
+ } else {
+ out.clear();
+ if (out_width != NULL) {
+ *out_width = 0;
+ }
+ if (out_height != NULL) {
+ *out_height = 0;
+ }
+ if (out_components != NULL) {
+ *out_components = 0;
+ }
+ PRINT_DEBUG("%s %p. reason: %s\n", "Failed to decode image at", &in, stbi_failure_reason());
+ }
+ }
+
+ return out;
+}
+
+std::string convert_png_buffer_std_string_to_std_string_uint8(std::string in, int * width, int * height, int * components, int desired_components) {
+ return convert_imgbuf_std_string_to_std_string_uint8(in, width, height, components, desired_components);
+}
+
+std::string convert_jpg_buffer_std_string_to_std_string_uint8(std::string in, int * width, int * height, int * components, int desired_components) {
+ return convert_imgbuf_std_string_to_std_string_uint8(in, width, height, components, desired_components);
+}
+
#ifdef NO_DISK_WRITES
std::string Local_Storage::get_program_path()
{
@@ -696,6 +831,57 @@ int Local_Storage::store_data_settings(std::string file, char *data, unsigned in
return store_file_data(get_global_settings_path(), file, data, length);
}
+int Local_Storage::copy_file_data(std::string src_full_path, std::string dest_full_path)
+{
+ std::ifstream srcfile;
+ std::ofstream destfile;
+ char * buf = NULL;
+ size_t readcount = 0;
+ const size_t bufsize = 1024;
+ bool fail = false;
+
+ buf = new char[bufsize];
+ if (buf == NULL) return -1;
+
+ srcfile.open(utf8_decode(src_full_path), std::ios::binary | std::ios::in);
+ if (!srcfile.is_open()) {
+ delete buf;
+ buf = NULL;
+ return -1;
+ }
+
+ destfile.open(utf8_decode(dest_full_path), std::ios::binary | std::ios::out);
+ if (!destfile.is_open()) {
+ delete buf;
+ buf = NULL;
+ srcfile.close();
+ return -1;
+ }
+
+ srcfile.seekg(0, std::ios::beg);
+ destfile.seekp(0, std::ios::beg);
+
+ do {
+ buf[readcount] = srcfile.get();
+ if (srcfile.eof() || (readcount + 1) == bufsize) {
+ destfile.write(buf, (readcount + 1));
+ readcount = 0;
+ } else {
+ readcount++;
+ }
+ if (srcfile.fail() || destfile.fail()) {
+ fail = true;
+ }
+ } while (srcfile.eof() == false && srcfile.fail() == false && destfile.fail() == false);
+
+ srcfile.close();
+ destfile.close();
+ reset_LastError();
+ delete buf;
+ buf = NULL;
+ return (!fail) ? 1 : 0;
+}
+
int Local_Storage::get_file_data(std::string full_path, char *data, unsigned int max_length, unsigned int offset)
{
std::ifstream myfile;
@@ -966,6 +1152,52 @@ std::vector Local_Storage::load_image(std::string const& image_pa
return res;
}
+int32_t Local_Storage::save_avatar_image(int32_t eAvatarSize, int32_t width, int32_t height, uint8_t * img_ptr)
+{
+ int32_t ret = 0;
+ std::string image_path = "";
+ switch (eAvatarSize) {
+ case k_EAvatarSize32x32:
+ if (width > 0 &&
+ width <= 32 &&
+ height > 0 &&
+ height <= 32) {
+ image_path += "avatar_small.";
+ }
+ break;
+ case k_EAvatarSize64x64:
+ if (width > 32 &&
+ width <= 64 &&
+ height > 32 &&
+ height <= 64) {
+ image_path += "avatar_medium.";
+ }
+ break;
+ case k_EAvatarSize184x184:
+ if (width > 64 &&
+ width <= 184 &&
+ height > 64 &&
+ height <= 184) {
+ image_path += "avatar_large.";
+ }
+ break;
+ case k_EAvatarSizeMAX:
+ default:
+ image_path.clear();
+ break;
+ };
+
+ if (image_path.length() > 0 && img_ptr != NULL) {
+ delete_data_settings(image_path + "jpg");
+ image_path += "png";
+ delete_data_settings(image_path);
+
+ image_path = get_global_settings_path() + image_path;
+ ret = (stbi_write_png(image_path.c_str(), width, height, 4, img_ptr, 0) == 1);
+ }
+ return ret;
+}
+
bool Local_Storage::save_screenshot(std::string const& image_path, uint8_t* img_ptr, int32_t width, int32_t height, int32_t channels)
{
std::string screenshot_path = std::move(save_directory + appid + screenshots_folder + PATH_SEPARATOR);
diff --git a/dll/local_storage.h b/dll/local_storage.h
index 078a932..6551a39 100644
--- a/dll/local_storage.h
+++ b/dll/local_storage.h
@@ -42,6 +42,11 @@ struct image_t
};
std::string convert_vector_image_pixel_t_to_std_string(std::vector & in);
+std::string convert_raw_uint8_to_png_std_string(uint8 * in, int width, int height, int components);
+std::string convert_raw_uint8_to_jpg_std_string(uint8 * in, int width, int height, int components);
+
+std::string convert_png_buffer_std_string_to_std_string_uint8(std::string in, int * width, int * height, int * components, int desired_components);
+std::string convert_jpg_buffer_std_string_to_std_string_uint8(std::string in, int * width, int * height, int * components, int desired_components);
class Local_Storage {
public:
@@ -67,6 +72,7 @@ public:
static bool is_directory(std::string &path);
Local_Storage(std::string save_directory);
static int get_file_data(std::string full_path, char *data, unsigned int max_length, unsigned int offset=0);
+ static int copy_file_data(std::string src_full_path, std::string dest_full_path);
void setAppId(uint32 appid);
static int store_file_data(std::string folder, std::string file, char *data, unsigned int length);
static std::vector get_filenames_path(std::string path);
@@ -94,6 +100,7 @@ public:
bool write_json_file(std::string folder, std::string const& file, nlohmann::json const& json);
std::vector load_image(std::string const& image_path, uint32_t * out_width, uint32_t * out_height);
+ int32_t save_avatar_image(int32_t eAvatarSize, int32_t width, int32_t height, uint8_t * img_ptr);
bool save_screenshot(std::string const& image_path, uint8_t* img_ptr, int32_t width, int32_t height, int32_t channels);
};
From c593c3f8b8248fbc065d8c0c3e8ec95826d026d0 Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Sat, 14 Dec 2024 20:01:17 -0500
Subject: [PATCH 43/67] Move most functionality from the macro to template.
Have the users of the macro use common functionality.
---
dll/dll.h | 157 +++++++++++++++++++++++++++++++++++++-----------------
1 file changed, 109 insertions(+), 48 deletions(-)
diff --git a/dll/dll.h b/dll/dll.h
index 1cfdbb0..7365ada 100644
--- a/dll/dll.h
+++ b/dll/dll.h
@@ -28,67 +28,128 @@
#define GOLDBERG_CALLBACK_INTERNAL(parent, fname, cb_type) \
struct GB_CCallbackInternal_ ## fname : private GB_CCallbackInterImp< sizeof(cb_type) > { \
public: \
- ~GB_CCallbackInternal_ ## fname () { if (m_nCallbackFlags & k_ECallbackFlagsRegistered) { \
- bool ready = false; \
- do { \
- if (global_mutex.try_lock() == true) { \
- Steam_Client * client = get_steam_client(); \
- if (client != NULL) { \
- get_steam_client()->UnregisterCallback(this); \
- ready = true; \
- } \
- global_mutex.unlock(); \
- } \
- } while (!ready); \
- } }\
- GB_CCallbackInternal_ ## fname () {} \
- GB_CCallbackInternal_ ## fname ( const GB_CCallbackInternal_ ## fname & ) {} \
- GB_CCallbackInternal_ ## fname & operator=(const GB_CCallbackInternal_ ## fname &) { return *this; } \
- private: \
+ GB_CCallbackInternal_ ## fname () { \
+ PRINT_DEBUG("GB_CCallbackInternal_%s::%s %s 0x%p.\n", \
+ #fname, \
+ #fname, \
+ "Default constructor", \
+ this); \
+ this->reg_thread_has_run = false; \
+ std::thread th = std::thread(GB_CCallbackInterImp::_register, this, cb_type::k_iCallback); \
+ th.detach(); \
+ } \
+ GB_CCallbackInternal_ ## fname ( const GB_CCallbackInternal_ ## fname & a ) { \
+ PRINT_DEBUG("GB_CCallbackInternal_%s::%s %s 0x%p.\n", \
+ #fname, \
+ #fname, \
+ "Copy constructor", \
+ this); \
+ this->reg_thread_has_run = false; \
+ std::thread th = std::thread(GB_CCallbackInterImp::_register, this, cb_type::k_iCallback); \
+ th.detach(); \
+ } \
+ GB_CCallbackInternal_ ## fname & operator=(const GB_CCallbackInternal_ ## fname &) { \
+ PRINT_DEBUG("GB_CCallbackInternal_%s::%s %s 0x%p.\n", \
+ #fname, \
+ #fname, \
+ "Assignment = operator", \
+ this); \
+ return *this; \
+ } \
virtual void Run(void *callback) { \
- if (!(m_nCallbackFlags & k_ECallbackFlagsRegistered)) { \
- bool ready = false; \
- do { \
- if (global_mutex.try_lock() == true) { \
- Steam_Client * client = get_steam_client(); \
- if (client != NULL) { \
- client->RegisterCallback(this, cb_type::k_iCallback); \
- ready = true; \
- } \
- global_mutex.unlock(); \
- } \
- } while (!ready); \
- } \
+ PRINT_DEBUG("GB_CCallbackInternal_%s::Run 0x%p Callback argument: 0x%p.\n", \
+ #fname, \
+ this, \
+ callback); \
if (m_nCallbackFlags & k_ECallbackFlagsRegistered) { \
parent *obj = reinterpret_cast(reinterpret_cast(this) - offsetof(parent, m_steamcallback_ ## fname)); \
obj->fname(reinterpret_cast(callback)); \
} \
- } \
- } m_steamcallback_ ## fname ; void fname( cb_type *callback )
+ } \
+ private: \
+ } m_steamcallback_ ## fname ; void fname(cb_type *callback )
template
class GB_CCallbackInterImp : protected CCallbackBase
{
public:
- virtual ~GB_CCallbackInterImp() { if (m_nCallbackFlags & k_ECallbackFlagsRegistered) {
- bool ready = false;
- do {
- if (global_mutex.try_lock() == true) {
- Steam_Client * client = get_steam_client();
- if (client != NULL) {
- get_steam_client()->UnregisterCallback(this);
- ready = true;
- }
- global_mutex.unlock();
- }
- } while (!ready);
- } }
- void SetGameserverFlag() { m_nCallbackFlags |= k_ECallbackFlagsGameServer; }
+ virtual ~GB_CCallbackInterImp() {
+ _unregister(this);
+ return;
+ }
+ void SetGameserverFlag() {
+ m_nCallbackFlags |= k_ECallbackFlagsGameServer;
+ return;
+ }
protected:
friend class CCallbackMgr;
+ std::atomic reg_thread_has_run;
virtual void Run(void *callback) = 0;
- virtual void Run( void *callback, bool io_failure, SteamAPICall_t api_fp) { Run(callback); }
- virtual int GetCallbackSizeBytes() { return sizeof_cb_type; }
+ virtual void Run(void *callback, bool io_failure, SteamAPICall_t api_fp) {
+ Run(callback);
+ return;
+ }
+ virtual int GetCallbackSizeBytes() {
+ return sizeof_cb_type;
+ }
+ static void _register(void * arg, int callback) {
+ GB_CCallbackInterImp * gb = (GB_CCallbackInterImp *)arg;
+ if (gb != NULL) {
+ PRINT_DEBUG("GB_CCallbackInterImp::_register Begin registration thread for 0x%p callback %d.\n",
+ gb,
+ callback);
+ if (!(gb->m_nCallbackFlags & k_ECallbackFlagsRegistered)) {
+ bool ready = false;
+ do {
+ if (global_mutex.try_lock() == true) {
+ Steam_Client * client = try_get_steam_client();
+ if (client != NULL) {
+ client->RegisterCallback(gb, callback);
+ ready = true;
+ gb->reg_thread_has_run = true;
+ PRINT_DEBUG("GB_CCallbackInterImp::_register Registration complete for 0x%p callback %d.\n",
+ gb,
+ callback);
+ }
+ global_mutex.unlock();
+ }
+ } while (!ready);
+ }
+ PRINT_DEBUG("GB_CCallbackInterImp::_register Exiting registration thread for 0x%p callback %d.\n",
+ gb,
+ callback);
+ }
+ return;
+ }
+ static void _unregister(void * arg) {
+ GB_CCallbackInterImp * gb = (GB_CCallbackInterImp *)arg;
+ if (gb != NULL) {
+ PRINT_DEBUG("GB_CCallbackInterImp::_unregister Begin deregistration thread for 0x%p.\n",
+ gb);
+ bool can_dereg = false;
+ do {
+ can_dereg = gb->reg_thread_has_run;
+ } while (!can_dereg);
+ if (gb->m_nCallbackFlags & k_ECallbackFlagsRegistered) {
+ bool ready = false;
+ do {
+ if (global_mutex.try_lock() == true) {
+ Steam_Client * client = try_get_steam_client();
+ if (client != NULL) {
+ client->UnregisterCallback(gb);
+ ready = true;
+ PRINT_DEBUG("GB_CCallbackInterImp::_unregister Deregistration complete for 0x%p.\n",
+ gb);
+ }
+ global_mutex.unlock();
+ }
+ } while (!ready);
+ PRINT_DEBUG("GB_CCallbackInterImp::_unregister Exiting deregistration thread for 0x%p.\n",
+ gb);
+ }
+ }
+ return;
+ }
};
Steam_Client *get_steam_client();
From 25d34a65c42d93f461612a860c5869ebd4cc8b3c Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Sat, 14 Dec 2024 20:04:28 -0500
Subject: [PATCH 44/67] Redo image handling in settings.
Lock the buffers when modifying them.
Notify when callers change a set avatar image.
Create a get function for images.
Allow deletion of previously loaded images, and reuse of their ids.
---
dll/settings.cpp | 224 +++++++++++++++++++++++++++++++++++++++++++++--
dll/settings.h | 28 ++++++
2 files changed, 243 insertions(+), 9 deletions(-)
diff --git a/dll/settings.cpp b/dll/settings.cpp
index 7d59938..cc9a8b7 100644
--- a/dll/settings.cpp
+++ b/dll/settings.cpp
@@ -16,7 +16,7 @@
. */
#include "settings.h"
-
+#include "dll.h"
std::string Settings::sanitize(std::string name)
{
@@ -54,6 +54,28 @@ Settings::Settings(CSteamID steam_id, CGameID game_id, std::string name, std::st
this->offline = offline;
this->create_unknown_leaderboards = true;
+
+ this->next_free = 1;
+ this->preferred_network_image_type = Image::JPG;
+
+ this->background_thread_exit = false;
+ PRINT_DEBUG("%s.\n", "Settings::Settings Creating new background_monitor thread");
+ background_monitor_thread = std::thread(Settings::background_monitor_entry, this);
+}
+
+Settings::~Settings()
+{
+ bool wait = false;
+ {
+ std::lock_guard lock(background_thread_mutex);
+ if (background_monitor_thread.joinable()) {
+ background_thread_exit = true;
+ wait = true;
+ }
+ }
+ if (wait) {
+ background_monitor_thread.join();
+ }
}
CSteamID Settings::get_local_steam_id()
@@ -214,19 +236,126 @@ void Settings::setLeaderboard(std::string leaderboard, enum ELeaderboardSortMeth
leaderboards[leaderboard] = leader;
}
+int Settings::find_next_free_image_ref() {
+ int ret = 0;
+
+ std::lock_guard lock(images_mutex);
+
+ if (images.size() == 0) {
+ ret = 1;
+ } else {
+ for (auto x : images) {
+ auto y = images.upper_bound(x.first);
+ if (y == images.end()) {
+ if ((x.first + 1) == 0) {
+ ret = 1;
+ break;
+ } else {
+ ret = x.first + 1;
+ break;
+ }
+ } else {
+ if ((x.first + 1) < y->first) {
+ if ((x.first + 1) != 0) {
+ ret = x.first + 1;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ next_free = ret;
+
+ return ret;
+}
+
+int Settings::remove_image(int ref) {
+ int ret = 0;
+
+ std::lock_guard lock(images_mutex);
+
+ auto x = images.find(ref);
+ if (x != images.end()) {
+ images.erase(x);
+ ret = find_next_free_image_ref();
+ } else {
+ ret = next_free;
+ }
+
+ return ret;
+}
+
+int Settings::replace_image(int ref, std::string data, uint32 width, uint32 height)
+{
+ std::lock_guard lock(images_mutex);
+ int ret = 0;
+ if (ref == 0) {
+ ret = add_image(data, width, height);
+ } else {
+ auto t = images.find(ref);
+ if (t != images.end()) {
+ ret = t->first;
+ t->second.data = data;
+ t->second.width = width;
+ t->second.height = height;
+ } else {
+ ret = add_image(data, width, height);
+ }
+ }
+ return ret;
+}
+
int Settings::add_image(std::string data, uint32 width, uint32 height)
{
- int last = images.size() + 1;
- struct Image_Data dt;
- dt.width = width;
- dt.height = height;
- dt.data = data;
- images[last] = dt;
+ int last = 0;
+ std::lock_guard lock(images_mutex);
+ if (next_free != 0) {
+ last = next_free;
+ struct Image_Data dt;
+ dt.width = width;
+ dt.height = height;
+ dt.data = data;
+ images[last] = dt;
+ find_next_free_image_ref();
+ } else {
+ PRINT_DEBUG("%s.\n",
+ "Settings::add_image failed. Buffer is full");
+ }
return last;
}
+int Settings::get_image(int ref, std::string * data, uint32 * width, uint32 * height)
+{
+ std::lock_guard lock(images_mutex);
+ int ret = 0;
+ auto t = images.find(ref);
+ if (t != images.end()) {
+ ret = t->first;
+ if (data != NULL) {
+ *data = t->second.data;
+ }
+ if (width != NULL) {
+ *width = t->second.width;
+ }
+ if (height != NULL) {
+ *height = t->second.height;
+ }
+ } else {
+ ret = 0;
+ if (width != NULL) {
+ *width = 0;
+ }
+ if (height != NULL) {
+ *height = 0;
+ }
+ }
+ return ret;
+}
+
int Settings::get_profile_image(int eAvatarSize)
{
+ std::lock_guard lock(images_mutex);
int ret = 0;
for (auto i : profile_images) {
if (i.first == eAvatarSize) {
@@ -237,6 +366,64 @@ int Settings::get_profile_image(int eAvatarSize)
return ret;
}
+void Settings::background_monitor_entry(Settings * settings) {
+ PRINT_DEBUG("%s.\n", "Settings::background_monitor_entry thread starting");
+ if (settings != NULL) {
+ settings->background_monitor();
+ }
+ PRINT_DEBUG("%s.\n", "Settings::background_monitor_entry thread exiting");
+ return;
+}
+
+void Settings::background_monitor() {
+ bool exit = false;
+ do {
+ {
+ std::lock_guard lock(background_thread_mutex);
+ exit = background_thread_exit;
+ if (!exit) {
+ if (background_tasks.size() > 0) {
+ for (auto x = background_tasks.begin(); x != background_tasks.end(); x++) {
+ bool task_done = false;
+ Steam_Client * client = try_get_steam_client();
+ if (client != NULL) {
+ switch (x->id) {
+ case Settings_Background_Task_IDs::NOTIFY_AVATAR_IMAGE:
+ {
+ PRINT_DEBUG("%s.\n", "Settings::background_monitor Got NOTIFY_AVATAR_IMAGE task");
+
+ if (client != NULL && client->steam_friends != NULL) {
+ client->steam_friends->GetFriendAvatar(this->steam_id, k_EAvatarSize32x32);
+ client->steam_friends->GetFriendAvatar(this->steam_id, k_EAvatarSize64x64);
+ client->steam_friends->GetFriendAvatar(this->steam_id, k_EAvatarSize184x184);
+ task_done = true;
+ }
+ }
+ break;
+ default:
+ PRINT_DEBUG("%s %d.\n", "Settings::background_monitor Unknown task", x->id);
+ task_done = true;
+ break;
+ };
+ if (task_done) {
+ background_tasks.erase(x);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ } while(!exit);
+ return;
+}
+
+void Settings::create_background_notify_task(Settings_Background_Task_IDs id, void *arg = NULL) {
+ std::lock_guard lock(background_thread_mutex);
+ background_tasks.push_back(Settings_Background_Task{id, arg});
+ return;
+}
+
int Settings::set_profile_image(int eAvatarSize, Image_Data * image)
{
bool size_ok = false;
@@ -252,11 +439,13 @@ int Settings::set_profile_image(int eAvatarSize, Image_Data * image)
if (size_ok == true && image->data.length() > 0) {
ref = this->add_image(image->data, image->width, image->height);
- PRINT_DEBUG("set_profile_image %d -> %d.\n", eAvatarSize, ref);
+ PRINT_DEBUG("Settings::set_profile_image %d -> %d.\n", eAvatarSize, ref);
+ std::lock_guard lock(images_mutex);
profile_images[eAvatarSize] = ref;
+ create_background_notify_task(Settings_Background_Task_IDs::NOTIFY_AVATAR_IMAGE, NULL);
} else {
PRINT_DEBUG("%s %d %dx%d %"PRI_ZU".\n",
- "set_profile_image failed",
+ "Settings::set_profile_image failed",
eAvatarSize,
image->width,
image->height,
@@ -266,3 +455,20 @@ int Settings::set_profile_image(int eAvatarSize, Image_Data * image)
return ref;
}
+
+void Settings::set_preferred_network_image_type(int new_type)
+{
+ switch (new_type) {
+ case Image::RAW:
+ case Image::PNG:
+ case Image::JPG:
+ this->preferred_network_image_type = new_type;
+ break;
+ default:
+ PRINT_DEBUG("%s %d.\n",
+ "Settings::set_preferred_network_image_type failed. Requested type",
+ new_type);
+ break;
+ };
+ return;
+}
diff --git a/dll/settings.h b/dll/settings.h
index 202c68c..8b7e7c2 100644
--- a/dll/settings.h
+++ b/dll/settings.h
@@ -65,11 +65,25 @@ struct Controller_Settings {
std::map, std::string>>> action_set_layers;
};
+enum Settings_Background_Task_IDs {
+ NOTIFY_AVATAR_IMAGE = 0
+};
+
+struct Settings_Background_Task {
+ enum Settings_Background_Task_IDs id;
+ void * arg;
+};
+
class Settings {
CSteamID steam_id;
CGameID game_id;
std::string name, language;
CSteamID lobby_id;
+ uint32 preferred_network_image_type;
+ bool background_thread_exit;
+ std::vector background_tasks;
+ std::thread background_monitor_thread;
+ std::recursive_mutex background_thread_mutex;
bool unlockAllDLCs;
bool offline;
@@ -83,6 +97,12 @@ class Settings {
std::map profile_images;
bool create_unknown_leaderboards;
uint16 port;
+ int next_free;
+
+ int find_next_free_image_ref();
+ void create_background_notify_task(Settings_Background_Task_IDs id, void *arg);
+ static void background_monitor_entry(Settings * settings);
+ void background_monitor();
public:
#ifdef LOBBY_CONNECT
@@ -90,8 +110,10 @@ public:
#else
static const bool is_lobby_connect = false;
#endif
+
static std::string sanitize(std::string name);
Settings(CSteamID steam_id, CGameID game_id, std::string name, std::string language, bool offline);
+ ~Settings();
CSteamID get_local_steam_id();
CGameID get_local_game_id();
const char *get_local_name();
@@ -146,10 +168,16 @@ public:
std::set subscribed_groups;
//images
+ std::recursive_mutex images_mutex;
std::map images;
+ int remove_image(int ref);
+ int replace_image(int ref, std::string data, uint32 width, uint32 height);
int add_image(std::string data, uint32 width, uint32 height);
+ int get_image(int ref, std::string * data, uint32 * width, uint32 * height);
int get_profile_image(int eAvatarSize);
int set_profile_image(int eAvatarSize, Image_Data * image);
+ int get_preferred_network_image_type() { return this->preferred_network_image_type; }
+ void set_preferred_network_image_type(int new_type);
//controller
struct Controller_Settings controller_settings;
From f693bfb07377e399b6e655bfb147e0dde4466303 Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Sat, 14 Dec 2024 20:11:11 -0500
Subject: [PATCH 45/67] Implement sending and receiving friend avatars.
Moves Steam_Friends::Callback into a cpp file.
Generates callbacks for avatar changes.
Requests avatars when asked for one that is unknown.
---
dll/base.h | 2 +-
dll/steam_friends.cpp | 425 ++++++++++++++++++++++++++++++++++++++++++
dll/steam_friends.h | 229 ++++++++++-------------
3 files changed, 523 insertions(+), 133 deletions(-)
create mode 100644 dll/steam_friends.cpp
diff --git a/dll/base.h b/dll/base.h
index fe59cba..6fa5cfe 100644
--- a/dll/base.h
+++ b/dll/base.h
@@ -325,12 +325,12 @@ public:
if (std::find(callbacks[iCallback].callbacks.begin(), callbacks[iCallback].callbacks.end(), cb) == callbacks[iCallback].callbacks.end()) {
callbacks[iCallback].callbacks.push_back(cb);
- CCallbackMgr::SetRegister(cb, iCallback);
for (auto & res: callbacks[iCallback].results) {
//TODO: timeout?
SteamAPICall_t api_id = results->addCallResult(iCallback, &(res[0]), res.size(), 0.0, false);
results->addCallBack(api_id, cb);
}
+ CCallbackMgr::SetRegister(cb, iCallback);
}
}
diff --git a/dll/steam_friends.cpp b/dll/steam_friends.cpp
new file mode 100644
index 0000000..dc87d9f
--- /dev/null
+++ b/dll/steam_friends.cpp
@@ -0,0 +1,425 @@
+/* Copyright (C) 2019 Mr Goldberg
+ This file is part of the Goldberg Emulator
+
+ The Goldberg Emulator is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ The Goldberg Emulator is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the Goldberg Emulator; if not, see
+ . */
+
+#include "steam_friends.h"
+#include "dll.h"
+
+void Steam_Friends::Callback(Common_Message *msg)
+{
+ if (msg->has_low_level()) {
+ if (msg->low_level().type() == Low_Level::DISCONNECT) {
+ PRINT_DEBUG("Steam_Friends::Callback Disconnect\n");
+ uint64 id = msg->source_id();
+ auto f = std::find_if(friends.begin(), friends.end(), [&id](Friend const& item) { return item.id() == id; });
+ if (friends.end() != f) {
+ persona_change((uint64)f->id(), k_EPersonaChangeStatus);
+ overlay->FriendDisconnect(*f);
+ if ((uint64)f->id() != settings->get_local_steam_id().ConvertToUint64()) {
+ auto nums = avatars.find((uint64)f->id());
+ if (nums != avatars.end()) {
+ if (nums->second.smallest != 0) {
+ settings->remove_image(nums->second.smallest);
+ }
+ if (nums->second.medium != 0) {
+ settings->remove_image(nums->second.medium);
+ }
+ if (nums->second.large != 0) {
+ settings->remove_image(nums->second.large);
+ }
+ avatars.erase(nums);
+ }
+ friends.erase(f);
+ }
+ }
+ }
+
+ if (msg->low_level().type() == Low_Level::CONNECT) {
+ PRINT_DEBUG("Steam_Friends::Callback Connect\n");
+ Common_Message msg_;
+ msg_.set_source_id(settings->get_local_steam_id().ConvertToUint64());
+ msg_.set_dest_id(msg->source_id());
+ Friend *f = new Friend(us);
+ f->set_id(settings->get_local_steam_id().ConvertToUint64());
+ f->set_name(settings->get_local_name());
+ f->set_appid(settings->get_local_game_id().AppID());
+ f->set_lobby_id(settings->get_lobby().ConvertToUint64());
+ msg_.set_allocated_friend_(f);
+ network->sendTo(&msg_, true);
+ }
+ }
+
+ if (msg->has_friend_()) {
+ PRINT_DEBUG("Steam_Friends::Callback Friend %llu %llu\n", msg->friend_().id(), msg->friend_().lobby_id());
+ Friend *f = find_friend((uint64)msg->friend_().id());
+ if (!f) {
+ if (msg->friend_().id() != settings->get_local_steam_id().ConvertToUint64()) {
+ friends.push_back(msg->friend_());
+ overlay->FriendConnect(msg->friend_());
+ persona_change((uint64)msg->friend_().id(), k_EPersonaChangeName);
+ }
+ } else {
+ std::map map1(f->rich_presence().begin(), f->rich_presence().end());
+ std::map map2(msg->friend_().rich_presence().begin(), msg->friend_().rich_presence().end());
+
+ if (map1 != map2) {
+ //The App ID of the game. This should always be the current game.
+ if (isAppIdCompatible(f)) {
+ rich_presence_updated((uint64)msg->friend_().id(), (uint64)msg->friend_().appid());
+ }
+ }
+ //TODO: callbacks?
+ *f = msg->friend_();
+ }
+ }
+
+ if (msg->has_friend_messages()) {
+ if (msg->friend_messages().type() == Friend_Messages::LOBBY_INVITE) {
+ PRINT_DEBUG("Steam_Friends::Callback Got Lobby Invite\n");
+ Friend *f = find_friend((uint64)msg->source_id());
+ if (f) {
+ LobbyInvite_t data;
+ data.m_ulSteamIDUser = msg->source_id();
+ data.m_ulSteamIDLobby = msg->friend_messages().lobby_id();
+ data.m_ulGameID = f->appid();
+ callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
+
+ if (overlay->Ready())
+ {
+ //TODO: the user should accept the invite first but we auto accept it because there's no gui yet
+ // Then we will handle it !
+ overlay->SetLobbyInvite(*find_friend(static_cast(msg->source_id())), msg->friend_messages().lobby_id());
+ }
+ else
+ {
+ GameLobbyJoinRequested_t data;
+ data.m_steamIDLobby = CSteamID((uint64)msg->friend_messages().lobby_id());
+ data.m_steamIDFriend = CSteamID((uint64)msg->source_id());
+ callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
+ }
+ }
+ }
+
+ if (msg->friend_messages().type() == Friend_Messages::GAME_INVITE) {
+ PRINT_DEBUG("Steam_Friends::Callback Got Game Invite\n");
+ //TODO: I'm pretty sure that the user should accept the invite before this is posted but we do like above
+ if (overlay->Ready())
+ {
+ // Then we will handle it !
+ overlay->SetRichInvite(*find_friend(static_cast(msg->source_id())), msg->friend_messages().connect_str().c_str());
+ }
+ else
+ {
+ std::string const& connect_str = msg->friend_messages().connect_str();
+ GameRichPresenceJoinRequested_t data = {};
+ data.m_steamIDFriend = CSteamID((uint64)msg->source_id());
+ strncpy(data.m_rgchConnect, connect_str.c_str(), k_cchMaxRichPresenceValueLength - 1);
+ callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
+ }
+ }
+ }
+
+ if (msg->has_friend_avatar()) {
+ CSteamID userID((uint64)msg->source_id());
+ Friend *f = find_friend(userID.ConvertToUint64());
+ if (f) {
+ if (msg->friend_avatar().img().type() == Image::NOTIFY) {
+ PRINT_DEBUG("%s %"PRIu64".\n", "Steam_Friends::Callback Got Friend_Avatar NOTIFY for", userID.ConvertToUint64());
+
+ std::string raw_image = msg->friend_avatar().img().img_data();
+ if (raw_image.length() > 0 && raw_image.length() < FRIEND_AVATAR_MAX_IMAGE_LENGTH) {
+ uint32_t width = (uint32_t)msg->friend_avatar().img().img_width();
+ uint32_t height = (uint32_t)msg->friend_avatar().img().img_height();
+ uint32_t img_type = (uint32_t)msg->friend_avatar().img().img_type();
+ int eAvatarSize = k_EAvatarSizeMAX;
+
+ auto nums = avatars.find(userID.ConvertToUint64());
+ if (nums == avatars.end()) {
+ struct Avatar_Numbers n;
+ generate_avatar_numbers(n);
+ n.last_update_time = std::chrono::steady_clock::now();
+ avatars[userID.ConvertToUint64()] = n;
+ nums = avatars.find(userID.ConvertToUint64());
+ }
+
+ int num_replace = 0;
+ if (nums != avatars.end()) {
+ if (width > 0 && width <= 32 && height > 0 && height <= 32) {
+ eAvatarSize = k_EAvatarSize32x32;
+ num_replace = nums->second.smallest;
+ } else {
+ if (width > 32 && width <= 64 && height > 32 && height <= 64) {
+ eAvatarSize = k_EAvatarSize64x64;
+ num_replace = nums->second.medium;
+ } else {
+ if (width > 64 && width <= 184 && height > 64 && height <= 184) {
+ eAvatarSize = k_EAvatarSize184x184;
+ num_replace = nums->second.large;
+ }
+ }
+ }
+
+ if (eAvatarSize != k_EAvatarSizeMAX) {
+
+ switch (img_type) {
+ case Image::RAW:
+ PRINT_DEBUG("%s %"PRIu64" %s %d %s.\n",
+ "Steam_Friends::Callback Got Friend_Avatar NOTIFY for",
+ userID.ConvertToUint64(),
+ "size",
+ eAvatarSize,
+ "image type RAW");
+ break;
+ case Image::JPG:
+ {
+ std::string convert;
+ int n_width = 0;
+ int n_height = 0;
+ PRINT_DEBUG("%s %"PRIu64" %s %d %s.\n",
+ "Steam_Friends::Callback Got Friend_Avatar NOTIFY for",
+ userID.ConvertToUint64(),
+ "size",
+ eAvatarSize,
+ "image type JPG");
+ convert = convert_jpg_buffer_std_string_to_std_string_uint8(raw_image, &n_width, &n_height, NULL, 4);
+ if (convert.length() > 0 && n_width == width && n_height == height) {
+ raw_image = convert;
+ convert.clear();
+ } else {
+ raw_image.clear();
+ }
+ }
+ break;
+ case Image::PNG:
+ {
+ std::string convert;
+ int n_width = 0;
+ int n_height = 0;
+ PRINT_DEBUG("%s %"PRIu64" %s %d %s.\n",
+ "Steam_Friends::Callback Got Friend_Avatar NOTIFY for",
+ userID.ConvertToUint64(),
+ "size",
+ eAvatarSize,
+ "image type PNG");
+ convert = convert_png_buffer_std_string_to_std_string_uint8(raw_image, &n_width, &n_height, NULL, 4);
+ if (convert.length() > 0 && n_width == width && n_height == height) {
+ raw_image = convert;
+ convert.clear();
+ } else {
+ raw_image.clear();
+ }
+ }
+ break;
+ default:
+ raw_image.clear();
+ PRINT_DEBUG("%s %"PRIu64" %s %d %s %d.\n",
+ "Steam_Friends::Callback Got Friend_Avatar NOTIFY for",
+ userID.ConvertToUint64(),
+ "size",
+ eAvatarSize,
+ "with unsupported image type",
+ img_type);
+ break;
+ };
+ if (raw_image.length() > 0) {
+ int ref = settings->replace_image(num_replace, raw_image, width, height);
+ if (ref != 0) {
+ nums->second.last_update_time = std::chrono::steady_clock::now();
+
+ AvatarImageLoaded_t ail_data = {};
+ ail_data.m_steamID = userID.ConvertToUint64();
+ ail_data.m_iImage = ref;
+ ail_data.m_iWide = width;
+ ail_data.m_iTall = height;
+ callback_results->addCallResult(ail_data.k_iCallback, &ail_data, sizeof(ail_data));
+ persona_change(userID, k_EPersonaChangeAvatar);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (msg->friend_avatar().img().type() == Image::REQUEST) {
+ CSteamID requestID((uint64)msg->dest_id());
+ if (settings->get_local_steam_id() == requestID) {
+ PRINT_DEBUG("%s %"PRIu64".\n", "Steam_Friends::Callback Got Friend_Avatar REQUEST from", userID.ConvertToUint64());
+
+ uint32_t width = (uint32_t)msg->friend_avatar().img().img_width();
+ uint32_t height = (uint32_t)msg->friend_avatar().img().img_height();
+ uint32_t img_type = (uint32_t)msg->friend_avatar().img().img_type();
+
+ int eAvatarSize = k_EAvatarSizeMAX;
+ if (width > 0 && width <= 32 && height > 0 && height <= 32) {
+ eAvatarSize = k_EAvatarSize32x32;
+ } else {
+ if (width > 32 && width <= 64 && height > 32 && height <= 64) {
+ eAvatarSize = k_EAvatarSize64x64;
+ } else {
+ if (width > 64 && width <= 184 && height > 64 && height <= 184) {
+ eAvatarSize = k_EAvatarSize184x184;
+ }
+ }
+ }
+
+ int ref = GetFriendAvatar(settings->get_local_steam_id(), eAvatarSize);
+ if (ref != 0) {
+
+ uint32 n_width = 0;
+ uint32 n_height = 0;
+ Steam_Utils* steamUtils = get_steam_client()->steam_utils;
+ if ((steamUtils->GetImageSize(ref, &n_width, &n_height) == true) &&
+ (n_width > 0) && (n_height > 0)) {
+ uint8 * raw_image = new uint8[(n_width * n_height * sizeof(uint32))];
+ if (raw_image != NULL) {
+ if (steamUtils->GetImageRGBA(ref,
+ raw_image,
+ (n_width * n_height * sizeof(uint32))) == true) {
+ uint32_t img_type = (uint32_t)msg->friend_avatar().img().img_type();
+ PRINT_DEBUG("%s %"PRIu64" %s %d %s %d.\n",
+ "Steam_Friends::Callback Got Friend_Avatar REQUEST from",
+ userID.ConvertToUint64(),
+ "for image type",
+ img_type,
+ "size",
+ eAvatarSize);
+
+ std::string pixdata = "";
+ if (img_type == Image::PNG) {
+ pixdata = convert_raw_uint8_to_png_std_string(raw_image, n_width, n_height, 4);
+ if (pixdata.length() <= 0 || pixdata.length() >= FRIEND_AVATAR_MAX_IMAGE_LENGTH) {
+ if (pixdata.length() >= FRIEND_AVATAR_MAX_IMAGE_LENGTH) {
+ PRINT_DEBUG("%s %"PRIu64" %s %d. %s %"PRI_ZU" %s.\n",
+ "Steam_Friends::Callback Cannot complete Friend_Avatar REQUEST from",
+ userID.ConvertToUint64(),
+ "for PNG image size",
+ eAvatarSize,
+ "Image is over maximum size by ",
+ pixdata.length() - FRIEND_AVATAR_MAX_IMAGE_LENGTH,
+ "bytes");
+ } else {
+ PRINT_DEBUG("%s %"PRIu64" %s %d. %s.\n",
+ "Steam_Friends::Callback Cannot complete Friend_Avatar REQUEST from",
+ userID.ConvertToUint64(),
+ "for PNG image size",
+ eAvatarSize,
+ "Could not convert image to requested type");
+ }
+
+ // Try again using JPG.
+ img_type = Image::JPG;
+ pixdata.clear();
+ }
+ }
+
+ if (img_type == Image::JPG) {
+ pixdata = convert_raw_uint8_to_jpg_std_string(raw_image, n_width, n_height, 4);
+ if (pixdata.length() <= 0 || pixdata.length() >= FRIEND_AVATAR_MAX_IMAGE_LENGTH) {
+ // Try again using RAW.
+ if (pixdata.length() >= FRIEND_AVATAR_MAX_IMAGE_LENGTH) {
+ PRINT_DEBUG("%s %"PRIu64" %s %d. %s %"PRI_ZU" %s.\n",
+ "Steam_Friends::Callback Cannot complete Friend_Avatar REQUEST from",
+ userID.ConvertToUint64(),
+ "for JPG image size",
+ eAvatarSize,
+ "Image is over maximum size by ",
+ pixdata.length() - FRIEND_AVATAR_MAX_IMAGE_LENGTH,
+ "bytes");
+ } else {
+ PRINT_DEBUG("%s %"PRIu64" %s %d. %s.\n",
+ "Steam_Friends::Callback Cannot complete Friend_Avatar REQUEST from",
+ userID.ConvertToUint64(),
+ "for JPG image size",
+ eAvatarSize,
+ "Could not convert image to requested type");
+ }
+ img_type = Image::RAW;
+ pixdata.clear();
+ }
+ }
+
+ if (img_type == Image::RAW) {
+ for (size_t x = 0; x < (n_width * n_height * sizeof(uint32)); x++) {
+ char a = (char)(raw_image[x]);
+ pixdata += a;
+ }
+ if (pixdata.length() <= 0 || pixdata.length() >= FRIEND_AVATAR_MAX_IMAGE_LENGTH) {
+ // No more attempts.
+ if (pixdata.length() >= FRIEND_AVATAR_MAX_IMAGE_LENGTH) {
+ PRINT_DEBUG("%s %"PRIu64" %s %d. %s %"PRI_ZU" %s.\n",
+ "Steam_Friends::Callback Cannot complete Friend_Avatar REQUEST from",
+ userID.ConvertToUint64(),
+ "for RAW image size",
+ eAvatarSize,
+ "Image is over maximum size by ",
+ pixdata.length() - FRIEND_AVATAR_MAX_IMAGE_LENGTH,
+ "bytes");
+ } else {
+ PRINT_DEBUG("%s %"PRIu64" %s %d. %s.\n",
+ "Steam_Friends::Callback Cannot complete Friend_Avatar REQUEST from",
+ userID.ConvertToUint64(),
+ "for RAW image size",
+ eAvatarSize,
+ "Could not convert image to requested type");
+ }
+ pixdata.clear();
+ }
+ }
+
+ if (img_type != Image::PNG && img_type != Image::JPG && img_type != Image::RAW) {
+ pixdata.clear();
+ PRINT_DEBUG("%s %"PRIu64" %s %d %s %d.\n",
+ "Steam_Friends::Callback Got Friend_Avatar REQUEST from",
+ userID.ConvertToUint64(),
+ "for unsupported image type",
+ img_type,
+ "size",
+ eAvatarSize);
+ }
+
+ if (pixdata.length() > 0 && pixdata.length() < FRIEND_AVATAR_MAX_IMAGE_LENGTH) {
+ PRINT_DEBUG("Steam_Friends::Callback Sending Friend_Avatar NOTIFY size %d type %d\n",
+ eAvatarSize,
+ img_type);
+ Common_Message msg_;
+ msg_.set_source_id(settings->get_local_steam_id().ConvertToUint64());
+ msg_.set_dest_id(msg->source_id());
+
+ Image *img = new Image();
+ img->set_type(Image::NOTIFY);
+ img->set_img_type(static_cast(img_type));
+ img->set_img_width(n_width);
+ img->set_img_height(n_height);
+ img->set_img_data(pixdata);
+
+ Friend_Avatar *friend_avatar = new Friend_Avatar();
+ friend_avatar->set_allocated_img(img);
+
+ msg_.set_allocated_friend_avatar(friend_avatar);
+ network->sendTo(&msg_, true);
+ }
+ }
+
+ delete raw_image;
+ raw_image = NULL;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/dll/steam_friends.h b/dll/steam_friends.h
index 7bce28e..f0b6970 100644
--- a/dll/steam_friends.h
+++ b/dll/steam_friends.h
@@ -27,6 +27,7 @@ struct Avatar_Numbers {
int smallest;
int medium;
int large;
+ std::chrono::steady_clock::time_point last_update_time;
};
class Steam_Friends :
@@ -94,39 +95,33 @@ bool isAppIdCompatible(Friend *f)
return settings->get_local_game_id().AppID() == f->appid();
}
+void generate_avatar_numbers(struct Avatar_Numbers & nums) {
+ std::string small_avatar(32 * 32 * 4, 0);
+ std::string medium_avatar(64 * 64 * 4, 0);
+ std::string large_avatar(184 * 184 * 4, 0);
+
+ nums.smallest = settings->add_image(small_avatar, 32, 32);
+ nums.medium = settings->add_image(medium_avatar, 64, 64);
+ nums.large = settings->add_image(large_avatar, 184, 184);
+ return;
+}
+
STEAM_CALL_RESULT( AvatarImageLoaded_t )
struct Avatar_Numbers add_friend_avatars(CSteamID id)
{
uint64 steam_id = id.ConvertToUint64();
auto avatar_ids = avatars.find(steam_id);
bool generate = true;
- int base_image = 0;
struct Avatar_Numbers avatar_numbers;
if (settings->get_local_steam_id().ConvertToUint64() == steam_id) {
avatar_numbers.smallest = settings->get_profile_image(k_EAvatarSize32x32);
- if (avatar_numbers.smallest != 0) {
- base_image = avatar_numbers.smallest;
- }
avatar_numbers.medium = settings->get_profile_image(k_EAvatarSize64x64);
- if (avatar_numbers.medium != 0) {
- base_image = avatar_numbers.medium;
- }
avatar_numbers.large = settings->get_profile_image(k_EAvatarSize184x184);
- if (avatar_numbers.large != 0) {
- base_image = avatar_numbers.large;
- }
- if (base_image != 0) {
+ if (avatar_numbers.smallest != 0 &&
+ avatar_numbers.medium != 0 &&
+ avatar_numbers.large != 0) {
generate = false;
- if (avatar_numbers.smallest == 0) {
- avatar_numbers.smallest = base_image;
- }
- if (avatar_numbers.medium == 0) {
- avatar_numbers.medium = base_image;
- }
- if (avatar_numbers.large == 0) {
- avatar_numbers.large = base_image;
- }
}
if (avatar_ids != avatars.end()) {
@@ -138,24 +133,77 @@ struct Avatar_Numbers add_friend_avatars(CSteamID id)
}
}
} else {
- //TODO: get real image data from other peers
-
if (avatar_ids != avatars.end()) {
- //TODO: Check for updated entry.
return avatar_ids->second;
+ } else {
+ // Request avatar data.
+ PRINT_DEBUG("Steam_Friends::add_friend_avatars sending Friend_Avatar small request for %"PRIu64".\n", steam_id);
+ Common_Message * msg_ = new Common_Message();
+ msg_->set_source_id(settings->get_local_steam_id().ConvertToUint64());
+ msg_->set_dest_id(steam_id);
+
+ Image *img = new Image();
+ img->set_type(Image::REQUEST);
+ img->set_img_type(static_cast(settings->get_preferred_network_image_type()));
+ img->set_img_width(32);
+ img->set_img_height(32);
+ img->set_img_data("");
+
+ Friend_Avatar *friend_avatar = new Friend_Avatar();
+ friend_avatar->set_allocated_img(img);
+
+ msg_->set_allocated_friend_avatar(friend_avatar);
+ network->sendTo(msg_, true);
+
+ PRINT_DEBUG("Steam_Friends::add_friend_avatars sending Friend_Avatar medium request for %"PRIu64".\n", steam_id);
+ msg_ = new Common_Message();
+ msg_->set_source_id(settings->get_local_steam_id().ConvertToUint64());
+ msg_->set_dest_id(steam_id);
+
+ img = new Image();
+ img->set_type(Image::REQUEST);
+ img->set_img_type(static_cast(settings->get_preferred_network_image_type()));
+ img->set_img_width(64);
+ img->set_img_height(64);
+ img->set_img_data("");
+
+ friend_avatar = new Friend_Avatar();
+ friend_avatar->set_allocated_img(img);
+
+ msg_->set_allocated_friend_avatar(friend_avatar);
+ network->sendTo(msg_, true);
+
+ PRINT_DEBUG("Steam_Friends::add_friend_avatars sending Friend_Avatar large request for %"PRIu64".\n", steam_id);
+ msg_ = new Common_Message();
+ msg_->set_source_id(settings->get_local_steam_id().ConvertToUint64());
+ msg_->set_dest_id(steam_id);
+
+ img = new Image();
+ img->set_type(Image::REQUEST);
+ img->set_img_type(static_cast(settings->get_preferred_network_image_type()));
+ img->set_img_width(184);
+ img->set_img_height(184);
+ img->set_img_data("");
+
+ friend_avatar = new Friend_Avatar();
+ friend_avatar->set_allocated_img(img);
+
+ msg_->set_allocated_friend_avatar(friend_avatar);
+ network->sendTo(msg_, true);
}
}
+ PRINT_DEBUG("%s %s %s %"PRIu64".\n",
+ "Steam_Friends::add_friend_avatars ",
+ (generate == true) ? "Generating empty" : "Notifying changed",
+ "avatar image for",
+ steam_id);
if (generate == true) {
- std::string small_avatar(32 * 32 * 4, 0);
- std::string medium_avatar(64 * 64 * 4, 0);
- std::string large_avatar(184 * 184 * 4, 0);
-
- avatar_numbers.smallest = settings->add_image(small_avatar, 32, 32);
- avatar_numbers.medium = settings->add_image(medium_avatar, 64, 64);
- avatar_numbers.large = settings->add_image(large_avatar, 184, 184);
+ generate_avatar_numbers(avatar_numbers);
}
+ avatar_numbers.last_update_time = std::chrono::steady_clock::now();
+
avatars[steam_id] = avatar_numbers;
// Generate callbacks.
@@ -254,6 +302,7 @@ Steam_Friends(Settings* settings, Networking* network, SteamCallResults* callbac
overlay(overlay)
{
this->network->setCallback(CALLBACK_ID_FRIEND, settings->get_local_steam_id(), &Steam_Friends::steam_friends_callback, this);
+ this->network->setCallback(CALLBACK_ID_FRIEND_AVATAR, settings->get_local_steam_id(), &Steam_Friends::steam_friends_callback, this);
this->network->setCallback(CALLBACK_ID_FRIEND_MESSAGES, settings->get_local_steam_id(), &Steam_Friends::steam_friends_callback, this);
this->network->setCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Friends::steam_friends_callback, this);
this->run_every_runcb->add(&Steam_Friends::steam_friends_run_every_runcb, this);
@@ -264,6 +313,20 @@ Steam_Friends(Settings* settings, Networking* network, SteamCallResults* callbac
{
//TODO rm network callbacks
this->run_every_runcb->remove(&Steam_Friends::steam_friends_run_every_runcb, this);
+
+ for (auto x : avatars) {
+ if (x.first != settings->get_local_steam_id().ConvertToUint64()) {
+ if (x.second.smallest != 0) {
+ settings->remove_image(x.second.smallest);
+ }
+ if (x.second.medium != 0) {
+ settings->remove_image(x.second.medium);
+ }
+ if (x.second.large != 0) {
+ settings->remove_image(x.second.large);
+ }
+ }
+ }
}
static bool ok_friend_flags(int iFriendFlags)
@@ -704,7 +767,7 @@ int GetSmallFriendAvatar( CSteamID steamIDFriend )
//IMPORTANT NOTE: don't change friend avatar numbers for the same friend or else some games endlessly allocate stuff.
std::lock_guard lock(global_mutex);
struct Avatar_Numbers numbers = add_friend_avatars(steamIDFriend);
- PRINT_DEBUG("Steam_Friends::GetSmallFriendAvatar%"PRIu64" %d.\n", steamIDFriend.ConvertToUint64(), numbers.smallest);
+ PRINT_DEBUG("Steam_Friends::GetSmallFriendAvatar %"PRIu64" -> %d.\n", steamIDFriend.ConvertToUint64(), numbers.smallest);
return numbers.smallest;
}
@@ -714,7 +777,7 @@ int GetMediumFriendAvatar( CSteamID steamIDFriend )
{
std::lock_guard lock(global_mutex);
struct Avatar_Numbers numbers = add_friend_avatars(steamIDFriend);
- PRINT_DEBUG("Steam_Friends::GetMediumFriendAvatar%"PRIu64" %d.\n", steamIDFriend.ConvertToUint64(), numbers.medium);
+ PRINT_DEBUG("Steam_Friends::GetMediumFriendAvatar %"PRIu64" -> %d.\n", steamIDFriend.ConvertToUint64(), numbers.medium);
return numbers.medium;
}
@@ -725,7 +788,7 @@ int GetLargeFriendAvatar( CSteamID steamIDFriend )
{
std::lock_guard lock(global_mutex);
struct Avatar_Numbers numbers = add_friend_avatars(steamIDFriend);
- PRINT_DEBUG("Steam_Friends::GetLargeFriendAvatar %"PRIu64" %d.\n", steamIDFriend.ConvertToUint64(), numbers.large);
+ PRINT_DEBUG("Steam_Friends::GetLargeFriendAvatar %"PRIu64" -> %d.\n", steamIDFriend.ConvertToUint64(), numbers.large);
return numbers.large;
}
@@ -1184,105 +1247,7 @@ void RunCallbacks()
}
}
-void Callback(Common_Message *msg)
-{
- if (msg->has_low_level()) {
- if (msg->low_level().type() == Low_Level::DISCONNECT) {
- PRINT_DEBUG("Steam_Friends Disconnect\n");
- uint64 id = msg->source_id();
- auto f = std::find_if(friends.begin(), friends.end(), [&id](Friend const& item) { return item.id() == id; });
- if (friends.end() != f) {
- persona_change((uint64)f->id(), k_EPersonaChangeStatus);
- overlay->FriendDisconnect(*f);
- friends.erase(f);
- }
- }
-
- if (msg->low_level().type() == Low_Level::CONNECT) {
- PRINT_DEBUG("Steam_Friends Connect\n");
- Common_Message msg_;
- msg_.set_source_id(settings->get_local_steam_id().ConvertToUint64());
- msg_.set_dest_id(msg->source_id());
- Friend *f = new Friend(us);
- f->set_id(settings->get_local_steam_id().ConvertToUint64());
- f->set_name(settings->get_local_name());
- f->set_appid(settings->get_local_game_id().AppID());
- f->set_lobby_id(settings->get_lobby().ConvertToUint64());
- msg_.set_allocated_friend_(f);
- network->sendTo(&msg_, true);
- }
- }
-
- if (msg->has_friend_()) {
- PRINT_DEBUG("Steam_Friends Friend %llu %llu\n", msg->friend_().id(), msg->friend_().lobby_id());
- Friend *f = find_friend((uint64)msg->friend_().id());
- if (!f) {
- if (msg->friend_().id() != settings->get_local_steam_id().ConvertToUint64()) {
- friends.push_back(msg->friend_());
- overlay->FriendConnect(msg->friend_());
- persona_change((uint64)msg->friend_().id(), k_EPersonaChangeName);
- }
- } else {
- std::map map1(f->rich_presence().begin(), f->rich_presence().end());
- std::map map2(msg->friend_().rich_presence().begin(), msg->friend_().rich_presence().end());
-
- if (map1 != map2) {
- //The App ID of the game. This should always be the current game.
- if (isAppIdCompatible(f)) {
- rich_presence_updated((uint64)msg->friend_().id(), (uint64)msg->friend_().appid());
- }
- }
- //TODO: callbacks?
- *f = msg->friend_();
- }
- }
-
- if (msg->has_friend_messages()) {
- if (msg->friend_messages().type() == Friend_Messages::LOBBY_INVITE) {
- PRINT_DEBUG("Steam_Friends Got Lobby Invite\n");
- Friend *f = find_friend((uint64)msg->source_id());
- if (f) {
- LobbyInvite_t data;
- data.m_ulSteamIDUser = msg->source_id();
- data.m_ulSteamIDLobby = msg->friend_messages().lobby_id();
- data.m_ulGameID = f->appid();
- callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
-
- if (overlay->Ready())
- {
- //TODO: the user should accept the invite first but we auto accept it because there's no gui yet
- // Then we will handle it !
- overlay->SetLobbyInvite(*find_friend(static_cast(msg->source_id())), msg->friend_messages().lobby_id());
- }
- else
- {
- GameLobbyJoinRequested_t data;
- data.m_steamIDLobby = CSteamID((uint64)msg->friend_messages().lobby_id());
- data.m_steamIDFriend = CSteamID((uint64)msg->source_id());
- callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
- }
- }
- }
-
- if (msg->friend_messages().type() == Friend_Messages::GAME_INVITE) {
- PRINT_DEBUG("Steam_Friends Got Game Invite\n");
- //TODO: I'm pretty sure that the user should accept the invite before this is posted but we do like above
- if (overlay->Ready())
- {
- // Then we will handle it !
- overlay->SetRichInvite(*find_friend(static_cast(msg->source_id())), msg->friend_messages().connect_str().c_str());
- }
- else
- {
- std::string const& connect_str = msg->friend_messages().connect_str();
- GameRichPresenceJoinRequested_t data = {};
- data.m_steamIDFriend = CSteamID((uint64)msg->source_id());
- strncpy(data.m_rgchConnect, connect_str.c_str(), k_cchMaxRichPresenceValueLength - 1);
- callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
- }
- }
- }
-}
+void Callback(Common_Message *msg);
};
From 4dbf130cb9c14342c6cb25938db25caf0af6d559 Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Mon, 16 Dec 2024 02:24:29 -0500
Subject: [PATCH 46/67] Allow checking registration for GB_CALLBACK
Add cb_type ## _is_registered function for GOLDBERG_CALLBACK_INTERNAL
macro to allow external checking of the callback's registration status
with CCallbackMgr.
---
dll/dll.h | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/dll/dll.h b/dll/dll.h
index 7365ada..6e75394 100644
--- a/dll/dll.h
+++ b/dll/dll.h
@@ -66,8 +66,15 @@
obj->fname(reinterpret_cast(callback)); \
} \
} \
+ bool isRegistered() { \
+ return ( m_nCallbackFlags & k_ECallbackFlagsRegistered ); \
+ } \
private: \
- } m_steamcallback_ ## fname ; void fname(cb_type *callback )
+ } m_steamcallback_ ## fname ; \
+ void fname(cb_type *callback) ; \
+ bool cb_type ## _is_registered() { \
+ return m_steamcallback_ ## fname.isRegistered(); \
+ }
template
class GB_CCallbackInterImp : protected CCallbackBase
From 57054031575b540f8d03ff5f59d8ca4a1c25ded8 Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Mon, 16 Dec 2024 02:29:33 -0500
Subject: [PATCH 47/67] Check callback registration in NOTIFY_AVATAR_IMAGE.
Make sure overlay callbacks are registered before firing callbacks for
set_profile_image.
---
dll/settings.cpp | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/dll/settings.cpp b/dll/settings.cpp
index cc9a8b7..a4f4045 100644
--- a/dll/settings.cpp
+++ b/dll/settings.cpp
@@ -393,10 +393,14 @@ void Settings::background_monitor() {
PRINT_DEBUG("%s.\n", "Settings::background_monitor Got NOTIFY_AVATAR_IMAGE task");
if (client != NULL && client->steam_friends != NULL) {
- client->steam_friends->GetFriendAvatar(this->steam_id, k_EAvatarSize32x32);
- client->steam_friends->GetFriendAvatar(this->steam_id, k_EAvatarSize64x64);
- client->steam_friends->GetFriendAvatar(this->steam_id, k_EAvatarSize184x184);
- task_done = true;
+ if (disable_overlay == true ||
+ (client->steam_overlay != NULL &&
+ client->steam_overlay->RegisteredInternalCallbacks() == true)) {
+ client->steam_friends->GetFriendAvatar(this->steam_id, k_EAvatarSize32x32);
+ client->steam_friends->GetFriendAvatar(this->steam_id, k_EAvatarSize64x64);
+ client->steam_friends->GetFriendAvatar(this->steam_id, k_EAvatarSize184x184);
+ task_done = true;
+ }
}
}
break;
From ba49e5618c752484d57ddd3589861080bacff70f Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Mon, 16 Dec 2024 02:31:54 -0500
Subject: [PATCH 48/67] Use correct callback queue for AvatarImageLoaded_t
---
dll/steam_friends.cpp | 2 +-
dll/steam_friends.h | 6 +++---
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/dll/steam_friends.cpp b/dll/steam_friends.cpp
index dc87d9f..00cf224 100644
--- a/dll/steam_friends.cpp
+++ b/dll/steam_friends.cpp
@@ -244,7 +244,7 @@ void Steam_Friends::Callback(Common_Message *msg)
ail_data.m_iImage = ref;
ail_data.m_iWide = width;
ail_data.m_iTall = height;
- callback_results->addCallResult(ail_data.k_iCallback, &ail_data, sizeof(ail_data));
+ callbacks->addCBResult(ail_data.k_iCallback, &ail_data, sizeof(ail_data));
persona_change(userID, k_EPersonaChangeAvatar);
}
}
diff --git a/dll/steam_friends.h b/dll/steam_friends.h
index f0b6970..16cfa05 100644
--- a/dll/steam_friends.h
+++ b/dll/steam_friends.h
@@ -226,7 +226,7 @@ struct Avatar_Numbers add_friend_avatars(CSteamID id)
ail_data.m_iImage = avatar_numbers.smallest;
ail_data.m_iWide = width;
ail_data.m_iTall = height;
- callback_results->addCallResult(ail_data.k_iCallback, &ail_data, sizeof(ail_data));
+ callbacks->addCBResult(ail_data.k_iCallback, &ail_data, sizeof(ail_data));
sent_ail = true;
}
@@ -244,7 +244,7 @@ struct Avatar_Numbers add_friend_avatars(CSteamID id)
ail_data.m_iImage = avatar_numbers.medium;
ail_data.m_iWide = width;
ail_data.m_iTall = height;
- callback_results->addCallResult(ail_data.k_iCallback, &ail_data, sizeof(ail_data));
+ callbacks->addCBResult(ail_data.k_iCallback, &ail_data, sizeof(ail_data));
sent_ail = true;
}
@@ -262,7 +262,7 @@ struct Avatar_Numbers add_friend_avatars(CSteamID id)
ail_data.m_iImage = avatar_numbers.large;
ail_data.m_iWide = width;
ail_data.m_iTall = height;
- callback_results->addCallResult(ail_data.k_iCallback, &ail_data, sizeof(ail_data));
+ callbacks->addCBResult(ail_data.k_iCallback, &ail_data, sizeof(ail_data));
sent_ail = true;
}
if (sent_ail) {
From 816479259b8726921c633a316503c9651ad96a9d Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Sat, 21 Dec 2024 05:29:33 -0500
Subject: [PATCH 49/67] Add Settings::ui_notification_position.
---
dll/common_includes.h | 2 ++
dll/settings.cpp | 23 +++++++++++++++++++++++
dll/settings.h | 6 +++++-
3 files changed, 30 insertions(+), 1 deletion(-)
diff --git a/dll/common_includes.h b/dll/common_includes.h
index bf612c4..dbc218f 100644
--- a/dll/common_includes.h
+++ b/dll/common_includes.h
@@ -219,6 +219,8 @@ inline std::string ascii_to_lowercase(std::string data) {
#define DEFAULT_LANGUAGE "english"
+#define DEFAULT_UI_NOTIFICATION_POSITION "top right"
+
#define LOBBY_CONNECT_APPID ((uint32)-2)
#define FRIEND_AVATAR_MAX_IMAGE_LENGTH (5 * 1024 * 1024)
diff --git a/dll/settings.cpp b/dll/settings.cpp
index a4f4045..8ca69c6 100644
--- a/dll/settings.cpp
+++ b/dll/settings.cpp
@@ -45,6 +45,8 @@ Settings::Settings(CSteamID steam_id, CGameID game_id, std::string name, std::st
this->name = this->name + " ";
}
+ this->ui_notification_position = "";
+
auto lang = sanitize(language);
std::transform(lang.begin(), lang.end(), lang.begin(), ::tolower);
lang.erase(std::remove(lang.begin(), lang.end(), ' '), lang.end());
@@ -476,3 +478,24 @@ void Settings::set_preferred_network_image_type(int new_type)
};
return;
}
+
+std::string Settings::get_ui_notification_position()
+{
+ return this->ui_notification_position;
+}
+
+void Settings::set_ui_notification_position(char * pos)
+{
+ PRINT_DEBUG("%s 0x%p.\n",
+ "Settings::set_ui_notification_position",
+ pos);
+ if (pos != NULL) {
+ size_t len = strlen(pos);
+ if (len > 0) {
+ this->ui_notification_position = "";
+ for (size_t x = 0; x < len && pos[x] != '\0'; x++) {
+ this->ui_notification_position += pos[x];
+ }
+ }
+ }
+}
diff --git a/dll/settings.h b/dll/settings.h
index 8b7e7c2..4c4b097 100644
--- a/dll/settings.h
+++ b/dll/settings.h
@@ -77,7 +77,7 @@ struct Settings_Background_Task {
class Settings {
CSteamID steam_id;
CGameID game_id;
- std::string name, language;
+ std::string name, language, ui_notification_position;
CSteamID lobby_id;
uint32 preferred_network_image_type;
bool background_thread_exit;
@@ -209,6 +209,10 @@ public:
void set_show_achievement_desc_on_unlock(bool set) { this->showAchievementDescOnUnlock = set; }
bool get_show_achievement_hidden_unearned() { return showAchievementHiddenUnearned; }
void set_show_achievement_hidden_unearned(bool set) { this->showAchievementHiddenUnearned = set; }
+
+ //UI
+ std::string get_ui_notification_position();
+ void set_ui_notification_position(char * pos);
};
#endif
From cd5d45e610d14b23a2d6f23dd7b9eb2a30227b5d Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Sat, 21 Dec 2024 05:32:11 -0500
Subject: [PATCH 50/67] Support saving / loading UI Notification Position.
---
dll/settings_parser.cpp | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/dll/settings_parser.cpp b/dll/settings_parser.cpp
index c75743f..413f5c0 100644
--- a/dll/settings_parser.cpp
+++ b/dll/settings_parser.cpp
@@ -260,6 +260,13 @@ uint32 create_localstorage_settings(Settings **settings_client_out, Settings **s
local_storage->store_data_settings("language.txt", language, strlen(language));
}
+ // UI Notification Position.
+ char notification_position[32] = {};
+ if (local_storage->get_data_settings("ui_notification_position.txt", notification_position, sizeof(notification_position) - 1) <= 0) {
+ strcpy(notification_position, DEFAULT_UI_NOTIFICATION_POSITION);
+ local_storage->store_data_settings("ui_notification_position.txt", notification_position, strlen(notification_position));
+ }
+
// Steam ID
char array_steam_id[32] = {};
CSteamID user_id;
@@ -394,6 +401,12 @@ uint32 create_localstorage_settings(Settings **settings_client_out, Settings **s
language[len] = 0;
warn_forced = true;
}
+ } else if (p == "force_ui_notification_position.txt") {
+ int len = Local_Storage::get_file_data(steam_settings_path + "force_ui_notification_position.txt", notification_position, sizeof(notification_position) - 1);
+ if (len > 0) {
+ notification_position[len] = 0;
+ warn_forced = true;
+ }
} else if (p == "force_steamid.txt") {
char steam_id_text[32] = {};
if (Local_Storage::get_file_data(steam_settings_path + "force_steamid.txt", steam_id_text, sizeof(steam_id_text) - 1) > 0) {
@@ -450,6 +463,8 @@ uint32 create_localstorage_settings(Settings **settings_client_out, Settings **s
settings_server->set_show_achievement_desc_on_unlock(enable_achievement_desc_on_unlock);
settings_client->set_show_achievement_hidden_unearned(enable_displaying_hidden_achievements);
settings_server->set_show_achievement_hidden_unearned(enable_displaying_hidden_achievements);
+ settings_client->set_ui_notification_position(notification_position);
+ settings_server->set_ui_notification_position(notification_position);
if (profile_small.data.length() > 0 && profile_small.width > 0 && profile_small.height > 0) {
settings_client->set_profile_image(k_EAvatarSize32x32, &profile_small);
settings_server->set_profile_image(k_EAvatarSize32x32, &profile_small);
@@ -729,9 +744,11 @@ void save_global_settings(Local_Storage *local_storage, Settings * client_settin
if ((local_storage != nullptr) && (client_settings != nullptr)) {
std::string name = client_settings->get_local_name();
std::string language = client_settings->get_language();
+ std::string ui_notif_pos = client_settings->get_ui_notification_position();
local_storage->store_data_settings("account_name.txt", (char*)name.c_str(), name.length());
local_storage->store_data_settings("language.txt", (char*)language.c_str(), language.length());
+ local_storage->store_data_settings("ui_notification_position.txt", (char*)ui_notif_pos.c_str(), ui_notif_pos.length());
if (client_settings->get_show_achievement_desc_on_unlock()) {
if (local_storage->data_settings_exists("enable_achievement_desc_on_unlock.txt") != true) {
local_storage->store_data_settings("enable_achievement_desc_on_unlock.txt", " ", sizeof(" "));
From 55b5118dc0f17cb6e548f49b0b93a4df79838495 Mon Sep 17 00:00:00 2001
From: redpolline <11156324-redpolline@users.noreply.gitlab.com>
Date: Sat, 21 Dec 2024 05:34:29 -0500
Subject: [PATCH 51/67] Add Overlay UI functions.
Too many things to list.
---
overlay_experimental/steam_overlay.cpp | 2260 +++++++++++++++++++++---
overlay_experimental/steam_overlay.h | 153 +-
2 files changed, 2203 insertions(+), 210 deletions(-)
diff --git a/overlay_experimental/steam_overlay.cpp b/overlay_experimental/steam_overlay.cpp
index fcbbf47..66e5dc9 100644
--- a/overlay_experimental/steam_overlay.cpp
+++ b/overlay_experimental/steam_overlay.cpp
@@ -50,8 +50,26 @@ static constexpr char *valid_languages[] = {
"vietnamese"
};
+static constexpr char *valid_ui_notification_position_labels[] = {
+ "top left",
+ "top right",
+ "bottom left",
+ "bottom right"
+};
+
#define URL_WINDOW_NAME "URL Window"
+class Steam_Overlay_CCallback
+{
+ private:
+ GOLDBERG_CALLBACK_INTERNAL(Steam_Overlay_CCallback, OnAvatarImageLoaded, AvatarImageLoaded_t);
+
+ public:
+ bool is_ready() {
+ return (AvatarImageLoaded_t_is_registered());
+ }
+};
+
int find_free_id(std::vector & ids, int base)
{
std::sort(ids.begin(), ids.end());
@@ -94,12 +112,273 @@ int find_free_notification_id(std::vector const& notifications)
return find_free_id(ids, base_friend_window_id);
}
+bool operator<(const Profile_Image_ID &a, const Profile_Image_ID &b) {
+ return ((a.id.ConvertToUint64() < b.id.ConvertToUint64()) && (a.eAvatarSize < b.eAvatarSize));
+}
+
+bool operator>(const Profile_Image_ID &a, const Profile_Image_ID &b) {
+ return (b < a);
+}
+
+bool operator<=(const Profile_Image_ID &a, const Profile_Image_ID &b) {
+ return !(a > b);
+}
+
+bool operator>=(const Profile_Image_ID &a, const Profile_Image_ID &b) {
+ return !(a < b);
+}
+
+bool operator==(const Profile_Image_ID &a, const Profile_Image_ID &b) {
+ return ((a.id.ConvertToUint64() == b.id.ConvertToUint64()) && (a.eAvatarSize == b.eAvatarSize));
+}
+
+bool operator!=(const Profile_Image_ID &a, const Profile_Image_ID &b) {
+ return !(a == b);
+}
+
+void Steam_Overlay::populate_initial_profile_images(CSteamID id = k_steamIDNil) {
+ bool found = false;
+ if (id == k_steamIDNil) {
+ id = settings->get_local_steam_id().ConvertToUint64();
+ }
+ for (auto & x : profile_images) {
+ if (x.first.ConvertToUint64() == id.ConvertToUint64()) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ profile_images[id] = Profile_Image_Set();
+ }
+ return;
+}
+
#ifdef __WINDOWS__
#include "windows/Windows_Hook.h"
#endif
#include "notification.h"
+bool Steam_Overlay::LoadProfileImage(const CSteamID & id, const int eAvatarSize) {
+ bool ret = false;
+ Profile_Image_Set new_images;
+ Profile_Image_Set old_images;
+
+ ret = LoadProfileImage(id, eAvatarSize, new_images);
+ if (ret == true) {
+ std::lock_guard lock(overlay_mutex);
+ auto entry = profile_images.find(id);
+ if (entry != profile_images.end()) {
+ if (eAvatarSize == k_EAvatarSize32x32) {
+ profile_images[id].small = new_images.small;
+ } else {
+ if (eAvatarSize == k_EAvatarSize64x64) {
+ profile_images[id].medium = new_images.medium;
+ } else {
+ if (eAvatarSize == k_EAvatarSize184x184) {
+ profile_images[id].large = new_images.large;
+ }
+ }
+ }
+ } else {
+ profile_images[id] = new_images;
+ }
+ }
+
+ return ret;
+}
+
+bool Steam_Overlay::LoadProfileImage(const CSteamID & id, const int eAvatarSize, Profile_Image_Set & images) {
+ PRINT_DEBUG("Steam_Overlay::LoadProfileImage() profile id %"PRIu64" size %d.\n", id.ConvertToUint64(), eAvatarSize);
+
+ bool ret = false;
+ Profile_Image * image = NULL;
+ uint32 width = 0;
+ uint32 height = 0;
+ Steam_Utils* steamUtils = get_steam_client()->steam_utils;
+ Steam_Friends* steamFriends = get_steam_client()->steam_friends;
+
+ if (eAvatarSize == k_EAvatarSize32x32)
+ image = &images.small;
+ if (eAvatarSize == k_EAvatarSize64x64)
+ image = &images.medium;
+ if (eAvatarSize == k_EAvatarSize184x184)
+ image = &images.large;
+
+ if (image != NULL) {
+ int image_handle = steamFriends->GetFriendAvatar(id, eAvatarSize);
+ if (image_handle != 0) {
+ if (steamUtils->GetImageSize(image_handle, &width, &height) == true &&
+ width > 0 &&
+ height > 0) {
+
+ PRINT_DEBUG("Steam_Overlay::LoadProfileImage() profile id %"PRIu64" size %d image_handle %d width %d height %d.\n",
+ id.ConvertToUint64(), eAvatarSize, image_handle, width, height);
+
+ if (image->raw_image != NULL) {
+ delete image->raw_image;
+ image->raw_image = NULL;
+ }
+ image->width = 0;
+ image->height = 0;
+ DestroyProfileImageResource(id, eAvatarSize);
+
+ uint8 * raw_image = new uint8[(width * height * sizeof(uint32))];
+ if (raw_image != NULL) {
+ if (steamUtils->GetImageRGBA(image_handle, raw_image, (width * height * sizeof(uint32))) == true) {
+ image->raw_image = raw_image;
+ image->width = width;
+ image->height = height;
+
+ ret = true;
+ } else {
+ delete raw_image;
+ raw_image = NULL;
+ PRINT_DEBUG("Steam_Overlay::LoadProfileImage() profile id %"PRIu64" size %d could not get pixel data.\n",
+ id.ConvertToUint64(), eAvatarSize);
+ }
+ }
+ } else {
+ PRINT_DEBUG("Steam_Overlay::LoadProfileImage() profile id %"PRIu64" size %d pixel data has invalid size.\n",
+ id.ConvertToUint64(), eAvatarSize);
+ }
+ } else {
+ PRINT_DEBUG("Steam_Overlay::LoadProfileImage() profile id %"PRIu64" size %d profile pixel data not loaded.\n",
+ id.ConvertToUint64(), eAvatarSize);
+ }
+ }
+
+ return ret;
+}
+
+void Steam_Overlay::DestroyProfileImage(const CSteamID & id, const int eAvatarSize) {
+ std::lock_guard lock(overlay_mutex);
+
+ for (auto & x : profile_images) {
+ if (x.first.ConvertToUint64() == id.ConvertToUint64()) {
+ DestroyProfileImage(id, eAvatarSize, x.second);
+ break;
+ }
+ }
+
+ return;
+}
+
+void Steam_Overlay::DestroyProfileImage(const CSteamID & id, const int eAvatarSize, Profile_Image_Set & images) {
+ PRINT_DEBUG("Steam_Overlay::DestroyProfileImage() %"PRIu64" size %d.\n", id.ConvertToUint64(), eAvatarSize);
+
+ Profile_Image * image = NULL;
+ std::lock_guard lock(overlay_mutex);
+
+ if (eAvatarSize == k_EAvatarSize32x32)
+ image = &images.small;
+ if (eAvatarSize == k_EAvatarSize64x64)
+ image = &images.medium;
+ if (eAvatarSize == k_EAvatarSize184x184)
+ image = &images.large;
+
+ if (image != NULL) {
+ if (image->raw_image != NULL) {
+ delete image->raw_image;
+ image->raw_image = NULL;
+ }
+ image->width = 0;
+ image->height = 0;
+ }
+
+ return;
+}
+
+bool Steam_Overlay::CreateProfileImageResource(const CSteamID & id, const int eAvatarSize) {
+ bool ret = false;
+ std::lock_guard lock(overlay_mutex);
+
+ for (auto & x : profile_images) {
+ if (x.first.ConvertToUint64() == id.ConvertToUint64()) {
+ ret = CreateProfileImageResource(id, eAvatarSize, x.second);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+bool Steam_Overlay::CreateProfileImageResource(const CSteamID & id, const int eAvatarSize, Profile_Image_Set & images) {
+ PRINT_DEBUG("Steam_Overlay::CreateProfileImageResource() %"PRIu64" size %d.\n", id.ConvertToUint64(), eAvatarSize);
+
+ bool ret = false;
+ Profile_Image * image = NULL;
+ std::lock_guard lock(overlay_mutex);
+
+ if (eAvatarSize == k_EAvatarSize32x32)
+ image = &images.small;
+ if (eAvatarSize == k_EAvatarSize64x64)
+ image = &images.medium;
+ if (eAvatarSize == k_EAvatarSize184x184)
+ image = &images.large;
+
+ if (_renderer) {
+ if (image->raw_image != NULL && image->width > 0 && image->height > 0 &&
+ image->image_resource.expired() == true) {
+ std::weak_ptr test;
+ test = _renderer->CreateImageResource(image->raw_image,
+ image->width,
+ image->height);
+ std::shared_ptr test2;
+ test2 = test.lock();
+ if (!test2) {
+ PRINT_DEBUG("Steam_Overlay::CreateProfileImageResource() Unable to create resource for profile id %"PRIu64" size %d.\n",
+ id.ConvertToUint64(), eAvatarSize);
+ } else {
+ image->image_resource = test;
+ ret = true;
+ PRINT_DEBUG("Steam_Overlay::CreateProfileImageResource() created resource for profile id %"PRIu64" size %d -> %"PRIu64".\n",
+ id.ConvertToUint64(), eAvatarSize, *test2);
+ }
+ } else {
+ PRINT_DEBUG("Steam_Overlay::CreateProfileImageResource() invalid raw data for profile id %"PRIu64" size %d.\n",
+ id.ConvertToUint64(), eAvatarSize);
+ }
+ }
+
+ return ret;
+}
+
+void Steam_Overlay::DestroyProfileImageResource(const CSteamID & id, const int eAvatarSize) {
+ std::lock_guard lock(overlay_mutex);
+
+ for (auto & x : profile_images) {
+ if (x.first.ConvertToUint64() == id.ConvertToUint64()) {
+ DestroyProfileImageResource(id, eAvatarSize, x.second);
+ break;
+ }
+ }
+
+ return;
+}
+
+void Steam_Overlay::DestroyProfileImageResource(const CSteamID & id, const int eAvatarSize, Profile_Image_Set & images)
+{
+ PRINT_DEBUG("Steam_Overlay::DestroyProfileImageResource() %"PRIu64" size %d.\n", id.ConvertToUint64(), eAvatarSize);
+
+ Profile_Image * image = NULL;
+ std::lock_guard lock(overlay_mutex);
+
+ if (eAvatarSize == k_EAvatarSize32x32)
+ image = &images.small;
+ if (eAvatarSize == k_EAvatarSize64x64)
+ image = &images.medium;
+ if (eAvatarSize == k_EAvatarSize184x184)
+ image = &images.large;
+
+ if (_renderer != NULL && image != NULL && image->image_resource.expired() == false) {
+ _renderer->ReleaseImageResource(image->image_resource);
+ image->image_resource.reset();
+ }
+
+ return;
+}
+
void Steam_Overlay::LoadAchievementImage(Overlay_Achievement & ach)
{
PRINT_DEBUG("LoadAchievementImage() %s.\n", ach.name.c_str());
@@ -116,32 +395,41 @@ void Steam_Overlay::LoadAchievementImage(Overlay_Achievement & ach)
PRINT_DEBUG("LoadAchievementImage() %d %d %d.\n", image_handle, width, height);
- if (ach.raw_image != NULL) {
- delete ach.raw_image;
- ach.raw_image = NULL;
+ {
+ std::lock_guard lock(overlay_mutex);
+ if (ach.raw_image != NULL) {
+ delete ach.raw_image;
+ ach.raw_image = NULL;
+ }
ach.raw_image_width = 0;
ach.raw_image_height = 0;
+ DestroyAchievementImageResource(ach);
}
- DestroyAchievementImageResource(ach);
uint8 * raw_image = new uint8[(width * height * sizeof(uint32))];
- if ((raw_image != NULL) &&
- (steamUtils->GetImageRGBA(image_handle,
- raw_image,
- (width * height * sizeof(uint32))) == true)) {
- PRINT_DEBUG("LoadAchievementImage() %d -> %p.\n", image_handle, raw_image);
- ach.raw_image = raw_image;
- ach.raw_image_width = width;
- ach.raw_image_height = height;
+ if (raw_image != NULL) {
+ if (steamUtils->GetImageRGBA(image_handle,
+ raw_image,
+ (width * height * sizeof(uint32))) == true) {
+ PRINT_DEBUG("LoadAchievementImage() %d -> %p.\n", image_handle, raw_image);
+ {
+ std::lock_guard lock(overlay_mutex);
+ ach.raw_image = raw_image;
+ ach.raw_image_width = width;
+ ach.raw_image_height = height;
+ }
+ } else {
+ delete raw_image;
+ PRINT_DEBUG("LoadAchievementImage() Achievement %s could not get pixel data.\n", ach.name.c_str());
+ }
} else {
- delete ach.raw_image;
- PRINT_DEBUG("Image for achievement %s could not get pixel data.\n", ach.name.c_str());
+ PRINT_DEBUG("LoadAchievementImage() Achievement %s could not allocate memory for pixel data.\n", ach.name.c_str());
}
} else {
- PRINT_DEBUG("Image for achievement %s has an invalid size.\n", ach.name.c_str());
+ PRINT_DEBUG("LoadAchievementImage() Achievement %s image pixel data has an invalid size.\n", ach.name.c_str());
}
} else {
- PRINT_DEBUG("Image for achievement %s is not loaded.\n", ach.name.c_str());
+ PRINT_DEBUG("LoadAchievementImage() Achievement %s is not loaded.\n", ach.name.c_str());
}
}
@@ -150,6 +438,7 @@ void Steam_Overlay::CreateAchievementImageResource(Overlay_Achievement & ach)
PRINT_DEBUG("CreateAchievementImageResource() %s. %d x %d -> %p\n", ach.name.c_str(), ach.raw_image_width, ach.raw_image_height, ach.raw_image);
if (_renderer) {
+ std::lock_guard lock(overlay_mutex);
if (ach.raw_image != NULL && ach.raw_image_width > 0 && ach.raw_image_height > 0 && ach.image_resource.expired() == true) {
std::weak_ptr test;
test = _renderer->CreateImageResource(ach.raw_image,
@@ -174,8 +463,12 @@ void Steam_Overlay::DestroyAchievementImageResource(Overlay_Achievement & ach)
{
PRINT_DEBUG("DestroyAchievementImageResource() %s.\n", ach.name.c_str());
- if (_renderer && ach.image_resource.expired() == false) {
- _renderer->ReleaseImageResource(ach.image_resource);
+ if (_renderer) {
+ std::lock_guard lock(overlay_mutex);
+ if (ach.image_resource.expired() == false) {
+ _renderer->ReleaseImageResource(ach.image_resource);
+ ach.image_resource.reset();
+ }
}
}
@@ -200,13 +493,18 @@ Steam_Overlay::Steam_Overlay(Settings* settings, SteamCallResults* callback_resu
setup_overlay_called(false),
show_overlay(false),
is_ready(false),
- notif_position(ENotificationPosition::k_EPositionBottomLeft),
+ notif_position(ENotificationPosition::k_EPositionTopRight),
+ current_ui_notification_position_selection(1), // valid_ui_notification_position_labels[1] == "top right"
h_inset(0),
v_inset(0),
overlay_state_changed(false),
i_have_lobby(false),
show_achievements(false),
show_settings(false),
+ show_profile_image_select(false),
+ show_drive_list(false),
+ tried_load_new_profile_image(false),
+ cleared_new_profile_images_struct(true),
_renderer(nullptr),
fonts_atlas(nullptr),
earned_achievement_count(0)
@@ -216,6 +514,10 @@ Steam_Overlay::Steam_Overlay(Settings* settings, SteamCallResults* callback_resu
show_achievement_desc_on_unlock = settings->get_show_achievement_desc_on_unlock();
show_achievement_hidden_unearned = settings->get_show_achievement_hidden_unearned();
+ radio_btn_new_profile_image_size[0] = false;
+ radio_btn_new_profile_image_size[1] = false;
+ radio_btn_new_profile_image_size[2] = true;
+
if (settings->warn_forced) {
this->disable_forced = true;
this->warning_forced = true;
@@ -230,10 +532,53 @@ Steam_Overlay::Steam_Overlay(Settings* settings, SteamCallResults* callback_resu
this->local_save = false;
}
+ int i = 0;
+ std::string ui_notif_pos = settings->get_ui_notification_position();
+ if (ui_notif_pos.length() > 0) {
+ for (auto n : valid_ui_notification_position_labels) {
+ if (strcmp(n, ui_notif_pos.c_str()) == 0) {
+ this->current_ui_notification_position_selection = i;
+ break;
+ }
+ ++i;
+ }
+ switch (i) {
+ case 0:
+ PRINT_DEBUG("%s.\n",
+ "Steam_Overlay::Steam_Overlay Got ui notification position from Settings: k_EPositionTopLeft");
+ this->notif_position = k_EPositionTopLeft;
+ break;
+ case 1:
+ PRINT_DEBUG("%s.\n",
+ "Steam_Overlay::Steam_Overlay Got ui notification position from Settings: k_EPositionTopRight");
+ this->notif_position = k_EPositionTopRight;
+ break;
+ case 2:
+ PRINT_DEBUG("%s.\n",
+ "Steam_Overlay::Steam_Overlay Got ui notification position from Settings: k_EPositionBottomLeft");
+ this->notif_position = k_EPositionBottomLeft;
+ break;
+ case 3:
+ PRINT_DEBUG("%s.\n",
+ "Steam_Overlay::Steam_Overlay Got ui notification position from Settings: k_EPositionBottomRight");
+ this->notif_position = k_EPositionBottomRight;
+ break;
+ default:
+ PRINT_DEBUG("%s %s. %s.\n",
+ "Steam_Overlay::Steam_Overlay Unrecognized ui notification position received from Settings: ",
+ ui_notif_pos.c_str(),
+ "Defaulting to k_EPositionTopRight");
+ break;
+ };
+ } else {
+ PRINT_DEBUG("%s.\n",
+ "Steam_Overlay::Steam_Overlay Settings does not have a ui notification position defined. Defaulting to k_EPositionTopRight");
+ }
+
current_language = 0;
const char *language = settings->get_language();
- int i = 0;
+ i = 0;
for (auto l : valid_languages) {
if (strcmp(l, language) == 0) {
current_language = i;
@@ -243,13 +588,22 @@ Steam_Overlay::Steam_Overlay(Settings* settings, SteamCallResults* callback_resu
++i;
}
+ populate_initial_profile_images();
+
run_every_runcb->add(&Steam_Overlay::steam_overlay_run_every_runcb, this);
this->network->setCallback(CALLBACK_ID_STEAM_MESSAGES, settings->get_local_steam_id(), &Steam_Overlay::steam_overlay_callback, this);
+ this->overlay_CCallback = new Steam_Overlay_CCallback();
}
Steam_Overlay::~Steam_Overlay()
{
+ std::lock_guard lock(overlay_mutex);
run_every_runcb->remove(&Steam_Overlay::steam_overlay_run_every_runcb, this);
+ if (this->overlay_CCallback != NULL) {
+ delete this->overlay_CCallback;
+ this->overlay_CCallback = NULL;
+ }
+
if (achievements.size()) {
for (auto & x : achievements) {
if (x.raw_image != NULL) {
@@ -261,6 +615,40 @@ Steam_Overlay::~Steam_Overlay()
DestroyAchievementImageResource(x);
}
}
+
+ if (profile_images.size()) {
+ for (auto & x : profile_images) {
+ if (x.second.small.raw_image != NULL) {
+ delete x.second.small.raw_image;
+ x.second.small.raw_image = NULL;
+ }
+ x.second.small.width = 0;
+ x.second.small.height = 0;
+
+ if (x.second.medium.raw_image != NULL) {
+ delete x.second.medium.raw_image;
+ x.second.medium.raw_image = NULL;
+ }
+ x.second.medium.width = 0;
+ x.second.medium.height = 0;
+
+ if (x.second.large.raw_image != NULL) {
+ delete x.second.large.raw_image;
+ x.second.large.raw_image = NULL;
+ }
+ x.second.large.width = 0;
+ x.second.large.height = 0;
+ }
+ }
+
+ DestroyProfileImageResources();
+
+ new_profile_image_handles.small.raw_image = NULL; // Handle
+ new_profile_image_handles.medium.raw_image = NULL; // Handle
+ new_profile_image_handles.large.raw_image = NULL; // Handle
+
+ DestroyTemporaryImageResources();
+ DestroyTemporaryImages();
}
bool Steam_Overlay::Ready() const
@@ -275,7 +663,37 @@ bool Steam_Overlay::NeedPresent() const
void Steam_Overlay::SetNotificationPosition(ENotificationPosition eNotificationPosition)
{
- notif_position = eNotificationPosition;
+ switch (eNotificationPosition) {
+ case k_EPositionTopLeft:
+ PRINT_DEBUG("%s.\n",
+ "Steam_Overlay::SetNotificationPosition Got ui notification position: k_EPositionTopLeft");
+ this->notif_position = k_EPositionTopLeft;
+ this->current_ui_notification_position_selection = 0;
+ break;
+ case k_EPositionTopRight:
+ PRINT_DEBUG("%s.\n",
+ "Steam_Overlay::SetNotificationPosition Got ui notification position: k_EPositionTopRight");
+ this->notif_position = k_EPositionTopRight;
+ this->current_ui_notification_position_selection = 1;
+ break;
+ case k_EPositionBottomLeft:
+ PRINT_DEBUG("%s.\n",
+ "Steam_Overlay::SetNotificationPosition Got ui notification position: k_EPositionBottomLeft");
+ this->notif_position = k_EPositionBottomLeft;
+ this->current_ui_notification_position_selection = 2;
+ break;
+ case k_EPositionBottomRight:
+ PRINT_DEBUG("%s.\n",
+ "Steam_Overlay::SetNotificationPosition Got ui notification position: k_EPositionBottomRight");
+ this->notif_position = k_EPositionBottomRight;
+ this->current_ui_notification_position_selection = 3;
+ break;
+ default:
+ PRINT_DEBUG("%s %d.\n",
+ "Steam_Overlay::SetNotificationPosition Unrecognized ui notification position received: ",
+ eNotificationPosition);
+ break;
+ };
}
void Steam_Overlay::SetNotificationInset(int nHorizontalInset, int nVerticalInset)
@@ -489,7 +907,7 @@ void Steam_Overlay::FriendDisconnect(Friend _friend)
friends.erase(it);
}
-void Steam_Overlay::AddMessageNotification(std::string const& message)
+void Steam_Overlay::AddMessageNotification(std::string const& message, CSteamID frd = k_steamIDNil)
{
std::lock_guard lock(notifications_mutex);
int id = find_free_notification_id(notifications);
@@ -499,6 +917,7 @@ void Steam_Overlay::AddMessageNotification(std::string const& message)
notif.id = id;
notif.type = notification_type_message;
notif.message = message;
+ notif.steam_id = frd;
notif.start_time = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch());
notifications.emplace_back(notif);
have_notifications = true;
@@ -568,6 +987,7 @@ void Steam_Overlay::AddInviteNotification(std::pair(std::chrono::system_clock::now().time_since_epoch());
notifications.emplace_back(notif);
have_notifications = true;
@@ -660,6 +1080,35 @@ void Steam_Overlay::BuildFriendWindow(Friend const& frd, friend_window_state& st
std::string friend_window_id = std::move("###" + std::to_string(state.id));
if (ImGui::Begin((state.window_title + friend_window_id).c_str(), &show))
{
+ ImGuiStyle currentStyle = ImGui::GetStyle();
+ ImVec2 image_offset(((ImGui::GetWindowWidth() * 0.04f) + currentStyle.FramePadding.x),
+ ((ImGui::GetWindowHeight() * 0.04f) + currentStyle.FramePadding.y +
+ ImGui::GetFontSize() + currentStyle.ItemSpacing.y)); // calc border.
+ ImVec2 image_max_resolution((ImGui::GetWindowWidth() - image_offset.x), (ImGui::GetWindowHeight() - image_offset.y)); // calc total space for image.
+ if (image_max_resolution.x > image_max_resolution.y) { // fix image aspect ratio. (square)
+ image_max_resolution.x = image_max_resolution.x - (image_max_resolution.x - image_max_resolution.y);
+ } else {
+ image_max_resolution.y = image_max_resolution.y - (image_max_resolution.y - image_max_resolution.x);
+ }
+ ImVec2 image_scale(image_max_resolution.x * 0.3f,
+ image_max_resolution.y * 0.3f);
+ ImVec2 text_offset(image_offset.x + image_scale.x + currentStyle.ItemSpacing.x,
+ image_offset.y + (image_scale.y * 0.2f) + currentStyle.ItemSpacing.y);
+ ImVec2 next_line_offset(currentStyle.FramePadding.x + currentStyle.ItemInnerSpacing.x,
+ image_offset.y + image_scale.y + (currentStyle.ItemSpacing.y * 2.0f));
+ ImGui::SetCursorPos(image_offset);
+
+ display_imgui_avatar(image_scale.x,
+ image_scale.y,
+ 1.0f, 1.0f, 1.0f, 1.0f,
+ CSteamID((uint64)frd.id()),
+ k_EAvatarSize184x184,
+ 0x1);
+ ImGui::SetCursorPos(text_offset);
+
+ ImGui::TextWrapped(std::string(frd.name() + " (" + std::to_string((uint64)frd.id()) + ")").c_str());
+ ImGui::SetCursorPos(next_line_offset);
+
if (state.window_state & window_state_need_attention && ImGui::IsWindowFocused())
{
state.window_state &= ~window_state_need_attention;
@@ -704,8 +1153,7 @@ void Steam_Overlay::BuildFriendWindow(Friend const& frd, friend_window_state& st
// | [__chat line__] [send] |
// |------------------------------|
float wnd_width = ImGui::GetWindowContentRegionWidth();
- ImGuiStyle &style = ImGui::GetStyle();
- wnd_width -= ImGui::CalcTextSize("Send").x + style.FramePadding.x * 2 + style.ItemSpacing.x + 1;
+ wnd_width -= ImGui::CalcTextSize("Send").x + currentStyle.FramePadding.x * 2 + currentStyle.ItemSpacing.x + 1;
ImGui::PushItemWidth(wnd_width);
if (ImGui::InputText("##chat_line", state.chat_input, max_chat_len, ImGuiInputTextFlags_EnterReturnsTrue))
@@ -783,7 +1231,29 @@ void Steam_Overlay::BuildNotifications(int width, int height)
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(255, 255, 255, Notification::max_alpha*2));
}
- ImGui::SetNextWindowPos(ImVec2((float)width - width * Notification::width, Notification::height * font_size * i ));
+ ImVec2 window_pos((float)width - width * Notification::width, Notification::height * font_size * i);
+
+ ImGuiViewport * viewport = ImGui::GetMainViewport();
+ if (viewport != NULL) {
+ if (notif_position == ENotificationPosition::k_EPositionBottomLeft ||
+ notif_position == ENotificationPosition::k_EPositionBottomRight) {
+ window_pos.y = ((viewport->Pos.y + viewport->Size.y) - Notification::height * font_size) - window_pos.y;
+ }
+ }
+ if (notif_position == ENotificationPosition::k_EPositionTopLeft ||
+ notif_position == ENotificationPosition::k_EPositionBottomLeft) {
+ window_pos.x = 0;
+ }
+
+ // Avoid overlay titlebar.
+ if (show_overlay == true &&
+ (notif_position == ENotificationPosition::k_EPositionTopLeft ||
+ notif_position == ENotificationPosition::k_EPositionTopRight)) {
+ window_pos.x += currentStyle.FramePadding.x + currentStyle.ItemSpacing.x;
+ window_pos.y += currentStyle.FramePadding.y + ImGui::GetFontSize() + currentStyle.ItemSpacing.y;
+ }
+
+ ImGui::SetNextWindowPos(window_pos);
ImGui::SetNextWindowSize(ImVec2( width * Notification::width, Notification::height * font_size ));
ImGui::Begin(std::to_string(it->id).c_str(), nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBringToFrontOnFocus |
ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoDecoration);
@@ -797,7 +1267,9 @@ void Steam_Overlay::BuildNotifications(int width, int height)
} else {
image_max_resolution.y = image_max_resolution.y - (image_max_resolution.y - image_max_resolution.x);
}
- ImVec2 text_offset(image_offset.x, image_offset.y);
+ ImVec2 image_scale(image_max_resolution.x * 0.4f,
+ image_max_resolution.y * 0.4f);
+ ImVec2 text_offset(image_offset.x + currentStyle.ItemSpacing.x + image_scale.x, image_offset.y);
ImGui::SetCursorPos(image_offset);
switch (it->type)
@@ -809,12 +1281,6 @@ void Steam_Overlay::BuildNotifications(int width, int height)
if ((a.image_resource.expired() == false) &&
(a.raw_image_width > 0) &&
(a.raw_image_height > 0)) {
- ImVec2 image_scale(image_max_resolution.x * 0.4f,
- image_max_resolution.y * 0.4f);
-
- // Fix text offset.
- text_offset.x = image_offset.x + currentStyle.ItemSpacing.x + image_scale.x;
-
std::shared_ptr s_ptr = a.image_resource.lock();
ImGui::Image((ImTextureID)(intptr_t)*s_ptr, image_scale, ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), image_color_multipler);
}
@@ -828,6 +1294,15 @@ void Steam_Overlay::BuildNotifications(int width, int height)
break;
case notification_type_invite:
{
+ display_imgui_avatar(image_scale.x,
+ image_scale.y,
+ image_color_multipler.x, // r
+ image_color_multipler.y, // g
+ image_color_multipler.z, // b
+ image_color_multipler.w, // a
+ it->steam_id,
+ k_EAvatarSize184x184,
+ 0x1);
ImGui::SetCursorPos(text_offset);
ImGui::TextWrapped("%s", it->message.c_str());
if (ImGui::Button("Join"))
@@ -839,8 +1314,18 @@ void Steam_Overlay::BuildNotifications(int width, int height)
}
break;
case notification_type_message:
+ display_imgui_avatar(image_scale.x,
+ image_scale.y,
+ image_color_multipler.x, // r
+ image_color_multipler.y, // g
+ image_color_multipler.z, // b
+ image_color_multipler.w, // a
+ it->steam_id,
+ k_EAvatarSize184x184,
+ 0x1);
ImGui::SetCursorPos(text_offset);
- ImGui::TextWrapped("%s", it->message.c_str()); break;
+ ImGui::TextWrapped("%s", it->message.c_str());
+ break;
}
ImGui::End();
@@ -872,6 +1357,7 @@ struct cb_font_str
ImFont * defaultFont;
HDC hDevice;
int foundBits;
+ std::recursive_mutex mutex;
};
static cb_font_str CBSTR;
@@ -909,10 +1395,13 @@ int LoadWindowsFontFromMem(const LOGFONT *lf)
oldFont = SelectObject(CBSTR.hDevice, hFont);
uint8_t metsize = GetOutlineTextMetrics(CBSTR.hDevice, 0, NULL);
if (metsize > 0) {
- OUTLINETEXTMETRIC * metric = (OUTLINETEXTMETRIC*)calloc(metsize, 1);
+ OUTLINETEXTMETRIC * metric = (OUTLINETEXTMETRIC*)malloc(metsize);
if (metric != NULL) {
+ memset(metric, '\0', metsize);
if (GetOutlineTextMetrics(CBSTR.hDevice, metsize, metric) != 0) {
- if ((metric->otmfsType & 0x1) == 0) {
+ // otmfsType: Bit 1 (May not be embedded if set.) Bit 2 (Read-Only embedding.)
+ // See also: https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-outlinetextmetrica
+ if ((((UINT)(metric->otmfsType)) & ((UINT)0x1) << 1) == 0) {
DWORD type = 0;
DWORD fontDataSize = LoadWindowsFontFromMem_GetSize_Helper(lf, &type);
if (fontDataSize != GDI_ERROR && fontDataSize > 4 && type != ~((DWORD)0)) {
@@ -974,7 +1463,7 @@ int LoadWindowsFontFromMem(const LOGFONT *lf)
PRINT_DEBUG("%s %d.\n", "GetFontData() failed. Unable to get initial size of font data. Ret: ", fontDataSize);
}
} else {
- PRINT_DEBUG("%s %s.\n", "Licensing failure. Cannot use font", lf->lfFaceName);
+ PRINT_DEBUG("%s %s. otmfsType data: %d.\n", "Licensing failure. Cannot use font", lf->lfFaceName, metric->otmfsType);
}
}
@@ -993,6 +1482,7 @@ int CALLBACK cb_enumfonts(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD fontTyp
{
int ret = 1; // Continue iteration.
cb_font_str * cbStr = &CBSTR;
+ std::lock_guard lock(cbStr->mutex);
if (CBSTR.atlas != NULL && lf != NULL && fontType == TRUETYPE_FONTTYPE) {
/*
foundBits:
@@ -1119,7 +1609,6 @@ void Steam_Overlay::CreateFonts()
HWND oWND = WindowFromDC(oDC);
int caps = GetDeviceCaps(oDC, RASTERCAPS);
if (caps != 0) {
-
int width = GetDeviceCaps(oDC, HORZRES);
int height = GetDeviceCaps(oDC, VERTRES);
HBITMAP hBitmap = CreateCompatibleBitmap(oDC, width, height);
@@ -1129,50 +1618,82 @@ void Steam_Overlay::CreateFonts()
lf.lfCharSet = DEFAULT_CHARSET;
lf.lfHeight = font_size;
lf.lfQuality = ANTIALIASED_QUALITY;
- memset(&CBSTR, '\0', sizeof(cb_font_str));
- CBSTR.font_size = font_size;
- CBSTR.fontcfg = fontcfg;
- CBSTR.atlas = Fonts;
- CBSTR.hDevice = CreateCompatibleDC(oDC);
- HGDIOBJ hOldBitmap = SelectObject(CBSTR.hDevice, hBitmap);
- DeleteObject(hOldBitmap);
+ HGDIOBJ hOldBitmap;
+ {
+ std::lock_guard lock(CBSTR.mutex);
+ CBSTR.font_size = font_size;
+ CBSTR.fontcfg = fontcfg;
+ CBSTR.atlas = Fonts;
+ CBSTR.defaultFont = NULL;
+ CBSTR.hDevice = CreateCompatibleDC(oDC);
+ CBSTR.foundBits = 0;
+ hOldBitmap = SelectObject(CBSTR.hDevice, hBitmap);
+ DeleteObject(hOldBitmap);
+ }
PRINT_DEBUG("%s\n", "Atempting to load preferred ANSI font from Win32 API.");
EnumFontFamiliesExA(CBSTR.hDevice, &lf, cb_enumfonts, 0, 0);
- if ((CBSTR.foundBits & 0x1) != 0x1) {
- CBSTR.foundBits = CBSTR.foundBits | 0x80;
+ bool resume_search = false;
+ {
+ std::lock_guard lock(CBSTR.mutex);
+ if ((CBSTR.foundBits & 0x1) != 0x1) {
+ CBSTR.foundBits = CBSTR.foundBits | 0x80;
+ resume_search = true;
+ }
+ }
+ if (resume_search) {
PRINT_DEBUG("%s\n", "Atempting to load generic ANSI font from Win32 API.");
EnumFontFamiliesExA(CBSTR.hDevice, &lf, cb_enumfonts, 0, 0);
- if ((CBSTR.foundBits & 0x1) != 0x1) {
- PRINT_DEBUG("%s\n", "Falling back to built in ImGUI ANSI font.");
- CBSTR.defaultFont = Fonts->AddFontDefault(&fontcfg);
- if (CBSTR.defaultFont == NULL) {
- PRINT_DEBUG("%s\n", "Built in ImGUI ANSI font failed to load. Weird text will probably happen.");
+ {
+ std::lock_guard lock(CBSTR.mutex);
+ if ((CBSTR.foundBits & 0x1) != 0x1) {
+ PRINT_DEBUG("%s\n", "Falling back to built in ImGUI ANSI font.");
+ CBSTR.defaultFont = Fonts->AddFontDefault(&fontcfg);
+ if (CBSTR.defaultFont == NULL) {
+ PRINT_DEBUG("%s\n", "Built in ImGUI ANSI font failed to load. Weird text will probably happen.");
+ }
+ CBSTR.foundBits = CBSTR.foundBits | 0x1;
}
- CBSTR.foundBits = CBSTR.foundBits | 0x1;
+ CBSTR.foundBits = CBSTR.foundBits ^ 0x80;
}
- CBSTR.foundBits = CBSTR.foundBits ^ 0x80;
}
- if ((CBSTR.foundBits & 0xE) != 0xE) {
+ resume_search = false;
+ {
+ std::lock_guard lock(CBSTR.mutex);
+ if ((CBSTR.foundBits & 0xE) != 0xE) {
+ resume_search = true;
+ }
+ }
+ if (resume_search) {
PRINT_DEBUG("%s\n", "Atempting to load preferred CJK fonts from Win32 API.");
EnumFontFamiliesExA(CBSTR.hDevice, &lf, cb_enumfonts, 0, 0);
}
- CBSTR.foundBits = CBSTR.foundBits | 0x80;
- if ((CBSTR.foundBits & 0xF) != 0xF) {
+ resume_search = false;
+ {
+ std::lock_guard lock(CBSTR.mutex);
+ CBSTR.foundBits = CBSTR.foundBits | 0x80;
+ if ((CBSTR.foundBits & 0xF) != 0xF) {
+ resume_search = true;
+ }
+ }
+ if (resume_search) {
PRINT_DEBUG("%s\n", "Loading generic CJK fonts from Win32 API.");
EnumFontFamiliesExA(CBSTR.hDevice, &lf, cb_enumfonts, 0, 0);
}
- if (CBSTR.defaultFont != NULL) {
- font = CBSTR.defaultFont;
- }
- if (need_extra_fonts == true) {
- if ((CBSTR.foundBits & 0xF) == 0xF) {
- need_extra_fonts = false;
+ {
+ std::lock_guard lock(CBSTR.mutex);
+ if (CBSTR.defaultFont != NULL) {
+ font = CBSTR.defaultFont;
+ }
+ if (need_extra_fonts == true) {
+ if ((CBSTR.foundBits & 0xF) == 0xF) {
+ need_extra_fonts = false;
+ }
}
- }
- DeleteDC(CBSTR.hDevice); // Order is important.
- DeleteObject(hBitmap);
+ DeleteDC(CBSTR.hDevice); // Order is important.
+ DeleteObject(hBitmap);
+ }
}
ReleaseDC(oWND, oDC);
#else
@@ -1203,10 +1724,188 @@ void Steam_Overlay::CreateFonts()
reset_LastError();
}
+void Steam_Overlay::ReturnTemporaryImage(Profile_Image & imageData)
+{
+ if (imageData.raw_image != NULL) {
+ delete imageData.raw_image;
+ imageData.raw_image = NULL;
+ }
+ imageData.width = 0;
+ imageData.height = 0;
+ return;
+}
+
+Profile_Image Steam_Overlay::GetTemporaryImage(uint8 * imageData)
+{
+ Profile_Image ret;
+
+ if (imageData != NULL) {
+ std::lock_guard lock(overlay_mutex);
+ for (auto & x : temp_display_images) {
+ if (x.first == imageData &&
+ x.second.image_data.raw_image != NULL &&
+ x.second.image_data.width > 0 &&
+ x.second.image_data.height > 0) {
+ size_t buffer_size = x.second.image_data.width * x.second.image_data.height * sizeof(uint32_t);
+ ret.raw_image = new uint8[buffer_size];
+ if (ret.raw_image != NULL) {
+ for (size_t y = 0; y < buffer_size; y++) {
+ uint8 a = x.second.image_data.raw_image[y];
+ ret.raw_image[y] = a;
+ }
+ ret.width = x.second.image_data.width;
+ ret.height = x.second.image_data.height;
+ x.second.last_display_time = std::chrono::steady_clock::now();
+ }
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+void Steam_Overlay::PruneTemporaryImages()
+{
+ std::lock_guard lock(overlay_mutex);
+ if (temp_display_images.size() > 0) {
+ for (auto & x : temp_display_images) {
+ if (x.second.last_display_time < (std::chrono::steady_clock::now() - std::chrono::minutes(1))) {
+ if (x.second.image_data.image_resource.expired() == false) {
+ if (_renderer) {
+ _renderer->ReleaseImageResource(x.second.image_data.image_resource);
+ x.second.image_data.image_resource.reset();
+ }
+ }
+ if (x.second.image_data.raw_image != NULL) {
+ delete x.second.image_data.raw_image;
+ x.second.image_data.raw_image = NULL;
+ }
+ x.second.image_data.width = 0;
+ x.second.image_data.height = 0;
+ }
+ }
+
+ bool done = false;
+ do {
+ if (temp_display_images.size() > 0) {
+ for (std::map::iterator x = temp_display_images.begin();
+ x != temp_display_images.end();
+ x++) {
+ std::map::iterator y = x;
+ y++;
+ if (y == temp_display_images.end()) {
+ done = true;
+ }
+ if ((x->second.image_data.image_resource.expired() == true) &&
+ x->second.image_data.raw_image == NULL &&
+ x->second.image_data.width <= 0 &&
+ x->second.image_data.height <= 0) {
+ temp_display_images.erase(x);
+ break;
+ }
+ }
+ } else {
+ done = true;
+ }
+ } while (!done);
+ }
+
+ return;
+}
+
+void Steam_Overlay::DestroyTemporaryImageResources()
+{
+ std::lock_guard lock(overlay_mutex);
+ for (auto & x : temp_display_images) {
+ if (x.second.image_data.image_resource.expired() == false) {
+ if (_renderer) {
+ _renderer->ReleaseImageResource(x.second.image_data.image_resource);
+ x.second.image_data.image_resource.reset();
+ }
+ }
+ }
+
+ return;
+}
+
+void Steam_Overlay::DestroyTemporaryImageResource(uint8 * imageData)
+{
+ std::lock_guard lock(overlay_mutex);
+ auto x = temp_display_images.find(imageData);
+ if (x != temp_display_images.end()) {
+ if (x->second.image_data.image_resource.expired() == false) {
+ if (_renderer) {
+ _renderer->ReleaseImageResource(x->second.image_data.image_resource);
+ x->second.image_data.image_resource.reset();
+ }
+ }
+ }
+
+ return;
+}
+
+void Steam_Overlay::DestroyTemporaryImages()
+{
+ std::lock_guard lock(overlay_mutex);
+ for (auto & x : temp_display_images) {
+ if (x.second.image_data.raw_image != NULL) {
+ delete x.second.image_data.raw_image;
+ x.second.image_data.raw_image = NULL;
+ }
+ x.second.image_data.width = 0;
+ x.second.image_data.height = 0;
+ }
+
+ return;
+}
+
+void Steam_Overlay::DestroyTemporaryImage(uint8 * imageData)
+{
+ std::lock_guard lock(overlay_mutex);
+ DestroyTemporaryImageResource(imageData);
+ auto x = temp_display_images.find(imageData);
+ if (x != temp_display_images.end()) {
+ if (x->second.image_data.raw_image != NULL) {
+ delete x->second.image_data.raw_image;
+ x->second.image_data.raw_image = NULL;
+ }
+ x->second.image_data.width = 0;
+ x->second.image_data.height = 0;
+ temp_display_images.erase(x);
+ }
+
+ return;
+}
+
+void Steam_Overlay::DestroyProfileImageResources()
+{
+ std::lock_guard lock(overlay_mutex);
+ for (auto & x : profile_images) {
+ if (x.second.small.image_resource.expired() == false) {
+ if (_renderer) {
+ DestroyProfileImageResource(x.first, k_EAvatarSize32x32, x.second);
+ }
+ }
+ if (x.second.medium.image_resource.expired() == false) {
+ if (_renderer) {
+ DestroyProfileImageResource(x.first, k_EAvatarSize64x64, x.second);
+ }
+ }
+ if (x.second.large.image_resource.expired() == false) {
+ if (_renderer) {
+ DestroyProfileImageResource(x.first, k_EAvatarSize184x184, x.second);
+ }
+ }
+ }
+
+ return;
+}
+
void Steam_Overlay::DestroyAchievementImageResources()
{
for (auto & x : achievements) {
- if (x.image_resource.expired()) {
+ if (x.image_resource.expired() == false) {
DestroyAchievementImageResource(x);
}
}
@@ -1214,6 +1913,455 @@ void Steam_Overlay::DestroyAchievementImageResources()
return;
}
+int Steam_Overlay::display_imgui_achievement(float xSize,
+ float ySize,
+ float image_color_multipler_r,
+ float image_color_multipler_g,
+ float image_color_multipler_b,
+ float image_color_multipler_a,
+ std::string achName,
+ uint32_t loadType = 0x0)
+{
+ return Steam_Overlay::display_imgui_image(displayImageTypeAchievement,
+ xSize,
+ ySize,
+ image_color_multipler_r,
+ image_color_multipler_g,
+ image_color_multipler_b,
+ image_color_multipler_a,
+ achName,
+ k_steamIDNil,
+ k_EAvatarSizeMAX,
+ NULL,
+ 0x0,
+ 0x0,
+ 0x0,
+ loadType);
+}
+
+int Steam_Overlay::display_imgui_avatar(float xSize,
+ float ySize,
+ float image_color_multipler_r,
+ float image_color_multipler_g,
+ float image_color_multipler_b,
+ float image_color_multipler_a,
+ CSteamID userID = k_steamIDNil,
+ int eAvatarSize = k_EAvatarSizeMAX,
+ uint32_t loadType = 0x0)
+{
+ return Steam_Overlay::display_imgui_image(displayImageTypeAvatar,
+ xSize,
+ ySize,
+ image_color_multipler_r,
+ image_color_multipler_g,
+ image_color_multipler_b,
+ image_color_multipler_a,
+ "",
+ userID,
+ eAvatarSize,
+ NULL,
+ 0x0,
+ 0x0,
+ 0x0,
+ loadType);
+}
+
+int Steam_Overlay::display_imgui_custom_image(float xSize,
+ float ySize,
+ float image_color_multipler_r,
+ float image_color_multipler_g,
+ float image_color_multipler_b,
+ float image_color_multipler_a,
+ uint8 * imageData = NULL,
+ uint32_t imageDataLength = 0x0,
+ uint32_t imageDataWidth = 0x0,
+ uint32_t imageDataHeight = 0x0)
+{
+ return Steam_Overlay::display_imgui_image(displayImageTypeCustom,
+ xSize,
+ ySize,
+ image_color_multipler_r,
+ image_color_multipler_g,
+ image_color_multipler_b,
+ image_color_multipler_a,
+ "",
+ k_steamIDNil,
+ k_EAvatarSizeMAX,
+ imageData,
+ imageDataLength,
+ imageDataWidth,
+ imageDataHeight,
+ 0x0);
+}
+
+int Steam_Overlay::display_imgui_image(uint32_t displayImageType,
+ float xSize,
+ float ySize,
+ float image_color_multipler_r,
+ float image_color_multipler_g,
+ float image_color_multipler_b,
+ float image_color_multipler_a,
+ std::string achName = "",
+ CSteamID userID = k_steamIDNil,
+ int eAvatarSize = k_EAvatarSizeMAX,
+ uint8 * imageData = NULL,
+ uint32_t imageDataLength = 0x0,
+ uint32_t imageDataWidth = 0x0,
+ uint32_t imageDataHeight = 0x0,
+ uint32_t loadType = 0x0)
+{
+ int ret = 0;
+ bool valid_args = false;
+ ImVec2 image_size(xSize, ySize);
+ ImVec4 image_color_multipler(image_color_multipler_r,
+ image_color_multipler_g,
+ image_color_multipler_b,
+ image_color_multipler_a);
+
+ switch (displayImageType) {
+ case displayImageTypeAchievement:
+ // Achievements
+ if (achName != "") {
+ valid_args = true;
+ for (auto & x : achievements) {
+ if (x.name == achName) {
+ if (loadType == 0x0) {
+ if (x.raw_image == NULL) {
+ LoadAchievementImage(x);
+ }
+ }
+
+ if (x.image_resource.expired() == true) {
+ CreateAchievementImageResource(x);
+ }
+
+ if ((x.image_resource.expired() == false) &&
+ (x.raw_image_width > 0) &&
+ (x.raw_image_height > 0)) {
+ std::shared_ptr s_ptr = x.image_resource.lock();
+ ImGui::Image((ImTextureID)(intptr_t)*s_ptr,
+ image_size,
+ ImVec2(0.0f, 0.0f),
+ ImVec2(1.0f, 1.0f),
+ image_color_multipler);
+ ret = 1;
+ }
+ break;
+ }
+ }
+ }
+ break;
+ case displayImageTypeAvatar:
+ // User Avatars
+ if (userID != k_steamIDNil) {
+ bool found_profile_images = false;
+ Profile_Image image;
+ {
+ std::lock_guard lock(overlay_mutex); // Can't hold this when calling LoadProfileImage().
+ for (auto & x : profile_images) {
+ if (x.first.ConvertToUint64() == userID.ConvertToUint64()) {
+ if (eAvatarSize == k_EAvatarSize32x32) {
+ image = x.second.small;
+ valid_args = true;
+ } else {
+ if (eAvatarSize == k_EAvatarSize64x64) {
+ image = x.second.medium;
+ valid_args = true;
+ } else {
+ if (eAvatarSize == k_EAvatarSize184x184) {
+ image = x.second.large;
+ valid_args = true;
+ } else {
+ valid_args = false;
+ }
+ }
+ }
+ found_profile_images = true;
+ break;
+ }
+ }
+ }
+
+ if (found_profile_images == false) {
+ populate_initial_profile_images(userID);
+ } else {
+ if (valid_args) {
+ bool reload = false;
+ if (image.raw_image == NULL ||
+ image.width == 0 ||
+ image.height == 0) {
+ if (loadType == 0x0) {
+ if (LoadProfileImage(userID, eAvatarSize) == true) {
+ reload = true;
+ PRINT_DEBUG("%s %d %s %"PRIu64" %s\n",
+ "Steam_Overlay::display_imgui_image Got avatar image size",
+ eAvatarSize,
+ "for user",
+ userID.ConvertToUint64(),
+ ". Load OK.");
+ } else{
+ PRINT_DEBUG("%s %d %s %"PRIu64" %s\n",
+ "Steam_Overlay::display_imgui_image Unable to get avatar image size",
+ eAvatarSize,
+ "for user",
+ userID.ConvertToUint64(),
+ ". Load Failure.");
+ }
+ } else {
+ uint32_t type = 0x0;
+ switch (eAvatarSize) {
+ case k_EAvatarSize32x32:
+ type |= 0x1;
+ break;
+ case k_EAvatarSize64x64:
+ type |= 0x2;
+ break;
+ case k_EAvatarSize184x184:
+ type |= 0x4;
+ break;
+ default:
+ type = 0x0;
+ break;
+ };
+
+ if (type != 0x0) {
+ PRINT_DEBUG("%s %"PRIu64" %s %d.\n",
+ "Steam_Overlay::display_imgui_image Queuing Lazy Load avatar image for",
+ userID.ConvertToUint64(),
+ "size",
+ eAvatarSize);
+ std::lock_guard lock(overlay_mutex); // Can't hold this when calling LoadProfileImage().
+ auto ld = lazy_load_avatar_images.find(userID);
+ if (ld == lazy_load_avatar_images.end()) {
+ type |= lazy_load_avatar_images[userID] & 0x7;
+ lazy_load_avatar_images[userID] = type;
+ } else {
+ lazy_load_avatar_images[userID] = type;
+ }
+ }
+ }
+ }
+
+ // Re-get list in case the map buffer was reallocated.
+ if (reload) {
+ found_profile_images = false;
+ valid_args = false;
+ {
+ std::lock_guard lock(overlay_mutex); // Can't hold this when calling LoadProfileImage().
+ for (auto & x : profile_images) {
+ if (x.first.ConvertToUint64() == userID.ConvertToUint64()) {
+ if (eAvatarSize == k_EAvatarSize32x32) {
+ image = x.second.small;
+ valid_args = true;
+ } else {
+ if (eAvatarSize == k_EAvatarSize64x64) {
+ image = x.second.medium;
+ valid_args = true;
+ } else {
+ if (eAvatarSize == k_EAvatarSize184x184) {
+ image = x.second.large;
+ valid_args = true;
+ } else {
+ valid_args = false;
+ }
+ }
+ }
+ found_profile_images = true;
+ break;
+ }
+ }
+ }
+ }
+
+ reload = false;
+ if (found_profile_images && valid_args && image.raw_image != NULL && image.width > 0 && image.height > 0) {
+ //if (!image.image_resource) {
+ if (image.image_resource.expired() == true) {
+
+ if (CreateProfileImageResource(userID, eAvatarSize) == true) {
+ reload = true;
+ PRINT_DEBUG("%s %d %s %"PRIu64" %s\n",
+ "Steam_Overlay::display_imgui_image Got profile image size",
+ eAvatarSize,
+ "for user",
+ userID.ConvertToUint64(),
+ ". Resource OK.");
+ } else {
+ PRINT_DEBUG("%s %d %s %"PRIu64" %s\n",
+ "Steam_Overlay::display_imgui_image Unable to get avatar image size",
+ eAvatarSize,
+ "for user",
+ userID.ConvertToUint64(),
+ ". Resource creation failure.");
+ }
+ }
+
+ // Re-get list in case the image resource was reallocated.
+ if (reload) {
+ found_profile_images = false;
+ valid_args = false;
+ {
+ std::lock_guard lock(overlay_mutex); // Can't hold this when calling LoadProfileImage().
+ for (auto & x : profile_images) {
+ if (x.first.ConvertToUint64() == userID.ConvertToUint64()) {
+ if (eAvatarSize == k_EAvatarSize32x32) {
+ image = x.second.small;
+ valid_args = true;
+ } else {
+ if (eAvatarSize == k_EAvatarSize64x64) {
+ image = x.second.medium;
+ valid_args = true;
+ } else {
+ if (eAvatarSize == k_EAvatarSize184x184) {
+ image = x.second.large;
+ valid_args = true;
+ } else {
+ valid_args = false;
+ }
+ }
+ }
+ found_profile_images = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (valid_args && found_profile_images && image.image_resource.expired() == false) {
+ std::shared_ptr test2;
+ test2 = image.image_resource.lock();
+ if (test2) {
+ ImGui::Image((ImTextureID)(intptr_t)*(test2),
+ image_size,
+ ImVec2(0.0f, 0.0f),
+ ImVec2(1.0f, 1.0f),
+ image_color_multipler);
+ ret = 1;
+ }
+ } else {
+ PRINT_DEBUG("%s %d %s %"PRIu64" %s\n",
+ "Steam_Overlay::display_imgui_image Unable to get avatar image size",
+ eAvatarSize,
+ "for user",
+ userID.ConvertToUint64(),
+ ". Resource Invalid.");
+ }
+ } else {
+ if (loadType == 0x0) {
+ PRINT_DEBUG("%s %d %s %"PRIu64" %s\n",
+ "Steam_Overlay::display_imgui_image Unable to display avatar image size",
+ eAvatarSize,
+ "for user",
+ userID.ConvertToUint64(),
+ ". Could not find buffer after pixel data load.");
+ }
+ }
+ }
+ }
+ }
+ break;
+ case displayImageTypeCustom:
+ // Custom image.
+ if (imageData != NULL) {
+ valid_args = true;
+ {
+ Temporary_Image new_temp_image;
+ std::lock_guard lock(overlay_mutex);
+ auto result = temp_display_images.find(imageData);
+ if (result != temp_display_images.end()) {
+ result->second.last_display_time = std::chrono::steady_clock::now();
+ } else {
+ if (imageDataLength > 0) {
+ uint8 * new_pixels = new uint8[(imageDataWidth * imageDataHeight * sizeof(uint32_t))];
+ if (new_pixels != NULL) {
+ for (size_t x = 0; x < (imageDataWidth * imageDataHeight * sizeof(uint32_t)) && x < imageDataLength; x++) {
+ new_pixels[x] = imageData[x];
+ }
+ new_temp_image.image_data.raw_image = new_pixels;
+ new_temp_image.image_data.width = imageDataWidth;
+ new_temp_image.image_data.height = imageDataHeight;
+ new_temp_image.last_display_time = std::chrono::steady_clock::now();
+ temp_display_images[imageData] = new_temp_image;
+ } else {
+ valid_args = false;
+ PRINT_DEBUG("%s %p. %s.\n",
+ "Steam_Overlay::display_imgui_image Unable to display custom image",
+ imageData,
+ "Could not allocate memory");
+ }
+ } else {
+ valid_args = false;
+ PRINT_DEBUG("%s %p. %s.\n",
+ "Steam_Overlay::display_imgui_image Unable to display custom image",
+ imageData,
+ "Image length not given, and image is not registered in temporary mappings");
+ }
+ }
+ }
+ if (valid_args == true) {
+ {
+ std::lock_guard lock(overlay_mutex);
+ auto result = temp_display_images.find(imageData);
+ if (result != temp_display_images.end()) {
+ if (result->second.image_data.image_resource.expired() == true) {
+ if (_renderer &&
+ result->second.image_data.raw_image != NULL &&
+ result->second.image_data.width > 0 &&
+ result->second.image_data.height > 0) {
+ std::weak_ptr test;
+ test = _renderer->CreateImageResource(result->second.image_data.raw_image,
+ result->second.image_data.width,
+ result->second.image_data.height);
+ std::shared_ptr test2;
+ test2 = test.lock();
+ if (!test2) {
+ PRINT_DEBUG("Steam_Overlay::display_imgui_image Unable to create resource for custom image %p.\n",
+ imageData);
+ _renderer->ReleaseImageResource(test);
+ } else {
+ PRINT_DEBUG("Steam_Overlay::display_imgui_image created resource for custom image %p -> %"PRIu64".\n",
+ imageData,
+ *test2);
+ result->second.image_data.image_resource = test;
+ }
+ }
+ }
+ }
+ }
+ {
+ std::lock_guard lock(overlay_mutex);
+ auto result = temp_display_images.find(imageData);
+ if (result != temp_display_images.end() &&
+ result->second.image_data.raw_image != NULL &&
+ result->second.image_data.width > 0 &&
+ result->second.image_data.height > 0 &&
+ result->second.image_data.image_resource.expired() == false) {
+ std::shared_ptr test2;
+ test2 = result->second.image_data.image_resource.lock();
+ if (test2) {
+ ImGui::Image((ImTextureID)(intptr_t)*(test2),
+ image_size,
+ ImVec2(0.0f, 0.0f),
+ ImVec2(1.0f, 1.0f),
+ image_color_multipler);
+ ret = 1;
+ }
+ }
+ }
+ }
+ }
+ break;
+ case displayImageTypeEND:
+ default:
+ PRINT_DEBUG("%s %d.\n",
+ "Steam_Overlay::display_imgui_image Unrecognized displayImageType: ",
+ displayImageType);
+ break;
+ };
+
+ return ret;
+}
+
// Try to make this function as short as possible or it might affect game's fps.
void Steam_Overlay::OverlayProc()
{
@@ -1244,128 +2392,147 @@ void Steam_Overlay::OverlayProc()
if (ImGui::Begin("SteamOverlay", &show, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoBringToFrontOnFocus))
{
- ImGui::LabelText("##label", "Username: %s(%llu) playing %u",
- settings->get_local_name(),
- settings->get_local_steam_id().ConvertToUint64(),
- settings->get_local_game_id().AppID());
- ImGui::SameLine();
+ bool user_image_displayed = false;
+ CSteamID local_user_id = settings->get_local_steam_id();
+ ImGuiStyle currentStyle = ImGui::GetStyle();
- ImGui::LabelText("##label", "Renderer: %s", (_renderer == nullptr ? "Unknown" : _renderer->GetLibraryName().c_str()));
+ user_image_displayed = (display_imgui_avatar(50.0f, 50.0f,
+ 1.0f, 1.0f, 1.0f, 1.0f,
+ local_user_id,
+ k_EAvatarSize184x184) == 1);
- ImGui::Text("Achievements earned: %d / %d", earned_achievement_count, total_achievement_count);
- ImGui::SameLine();
- ImGui::ProgressBar((earned_achievement_count / total_achievement_count), ImVec2((io.DisplaySize.x * 0.20f),0));
-
- ImGui::Spacing();
- if (ImGui::Button("Show Achievements")) {
- show_achievements = true;
- }
-
- ImGui::SameLine();
-
- if (ImGui::Button("Settings")) {
- show_settings = true;
- }
-
- ImGui::Spacing();
- ImGui::Spacing();
-
- ImGui::LabelText("##label", "Friends");
-
- std::lock_guard lock(overlay_mutex);
- if (!friends.empty())
{
- if (ImGui::ListBoxHeader("##label", friends.size()))
+ std::lock_guard lock(overlay_mutex);
+
+ ImGui::LabelText("##label", "Username: %s(%llu) playing %u",
+ settings->get_local_name(),
+ local_user_id.ConvertToUint64(),
+ settings->get_local_game_id().AppID());
+ ImGui::SameLine();
+
+ ImGui::LabelText("##label", "Renderer: %s", (_renderer == nullptr ? "Unknown" : _renderer->GetLibraryName().c_str()));
+
+ ImGui::Text("Achievements earned: %d / %d", earned_achievement_count, total_achievement_count);
+ ImGui::SameLine();
+ ImGui::ProgressBar((earned_achievement_count / total_achievement_count), ImVec2((io.DisplaySize.x * 0.20f),0));
+
+ ImGui::Spacing();
+ if (ImGui::Button("Show Achievements")) {
+ show_achievements = true;
+ }
+
+ ImGui::SameLine();
+
+ if (ImGui::Button("Settings")) {
+ show_settings = true;
+ }
+
+ ImGui::Spacing();
+ ImGui::Spacing();
+
+ ImGui::LabelText("##label", "Friends");
+
+ if (!friends.empty())
{
- std::for_each(friends.begin(), friends.end(), [this](std::pair &i)
+ if (ImGui::ListBoxHeader("##label", friends.size()))
{
- ImGui::PushID(i.second.id-base_friend_window_id+base_friend_item_id);
-
- ImGui::Selectable(i.second.window_title.c_str(), false, ImGuiSelectableFlags_AllowDoubleClick);
- BuildContextMenu(i.first, i.second);
- if (ImGui::IsItemClicked() && ImGui::IsMouseDoubleClicked(0))
+ std::for_each(friends.begin(), friends.end(), [this](std::pair &i)
{
- i.second.window_state |= window_state_show;
- }
- ImGui::PopID();
+ ImGui::PushID(i.second.id-base_friend_window_id+base_friend_item_id);
- BuildFriendWindow(i.first, i.second);
- });
- ImGui::ListBoxFooter();
- }
- }
-
- if (show_achievements && achievements.size()) {
- ImGui::SetNextWindowSizeConstraints(ImVec2(ImGui::GetFontSize() * 32, ImGui::GetFontSize() * 32), ImVec2(8192, 8192));
- bool show = show_achievements;
- if (ImGui::Begin("Achievement Window", &show)) {
- ImGui::Text("List of achievements");
- ImGui::BeginChild("Achievements");
- ImGuiStyle currentStyle = ImGui::GetStyle();
- float window_x_offset = (ImGui::GetWindowWidth() > currentStyle.ScrollbarSize) ? (ImGui::GetWindowWidth() - currentStyle.ScrollbarSize) : 0;
- for (auto & x : achievements) {
- bool achieved = x.achieved;
- bool hidden = x.hidden && !achieved;
-
- if (!hidden || show_achievement_hidden_unearned) {
-
- if (x.raw_image == NULL) {
- LoadAchievementImage(x);
+ // Selectable "" + SameLine + Image + Text == all highlighted.
+ // See also: https://github.com/ocornut/imgui/issues/1658#issuecomment-373731255
+ ImGui::Selectable("", false, ImGuiSelectableFlags_AllowDoubleClick);
+ BuildContextMenu(i.first, i.second);
+ if (ImGui::IsItemClicked() && ImGui::IsMouseDoubleClicked(0))
+ {
+ i.second.window_state |= window_state_show;
}
+ ImGui::PopID();
- if (x.image_resource.expired() == true) {
- CreateAchievementImageResource(x);
+ ImGui::SameLine();
+
+ if (display_imgui_avatar(32 * 0.4f, 32 * 0.4f,
+ 1.0f, 1.0f, 1.0f, 1.0f,
+ CSteamID((uint64)i.first.id()),
+ k_EAvatarSize32x32,
+ 0x1) != 1) {
+ ImGui::ColorButton("test", ImVec4(255, 0, 0, 255), 0, ImVec2(32 * 0.4f, 32 * 0.4f));
+ PRINT_DEBUG("%s %"PRIu64".\n",
+ "SteamOverlay::OverlayProc Failed to display friend avatar for",
+ (uint64)i.first.id());
}
+ ImGui::SameLine();
- ImGui::Separator();
+ ImGui::Text(i.second.window_title.c_str());
- // Anchor the image to the right side of the list.
- ImVec2 target = ImGui::GetCursorPos();
- target.x = window_x_offset;
- if (target.x > (x.raw_image_width * 0.4f)) {
- target.x = target.x - (x.raw_image_width * 0.4f);
- } else {
- target.x = 0;
- }
-
- ImGui::PushTextWrapPos(target.x);
- ImGui::Text("%s", x.title.c_str());
- if (hidden) {
- ImGui::Text("Hidden Achievement");
- } else {
- ImGui::Text("%s", x.description.c_str());
- }
- ImGui::PopTextWrapPos();
-
- if (achieved) {
- char buffer[80] = {};
- time_t unlock_time = (time_t)x.unlock_time;
- std::strftime(buffer, 80, "%Y-%m-%d at %H:%M:%S", std::localtime(&unlock_time));
-
- ImGui::TextColored(ImVec4(0, 255, 0, 255), "achieved on %s", buffer);
- } else {
- ImGui::TextColored(ImVec4(255, 0, 0, 255), "not achieved");
- }
-
- // Set cursor for image output.
- if (target.x != 0) {
- ImGui::SetCursorPos(target);
- }
-
- if ((x.image_resource.expired() == false) &&
- (x.raw_image_width > 0) &&
- (x.raw_image_height > 0)) {
- std::shared_ptr s_ptr = x.image_resource.lock();
- ImGui::Image((ImTextureID)(intptr_t)*s_ptr, ImVec2(x.raw_image_width * 0.4f, x.raw_image_height * 0.4f));
- }
-
- ImGui::Separator();
- }
+ BuildFriendWindow(i.first, i.second);
+ });
+ ImGui::ListBoxFooter();
}
- ImGui::EndChild();
}
- ImGui::End();
- show_achievements = show;
+
+ if (show_achievements && achievements.size()) {
+ ImGui::SetNextWindowSizeConstraints(ImVec2(ImGui::GetFontSize() * 32, ImGui::GetFontSize() * 32), ImVec2(8192, 8192));
+ bool show = show_achievements;
+ if (ImGui::Begin("Achievement Window", &show)) {
+ ImGui::Text("List of achievements");
+ ImGui::BeginChild("Achievements");
+ float window_x_offset = (ImGui::GetWindowWidth() > currentStyle.ScrollbarSize) ? (ImGui::GetWindowWidth() - currentStyle.ScrollbarSize) : 0;
+ for (auto & x : achievements) {
+ bool achieved = x.achieved;
+ bool hidden = x.hidden && !achieved;
+
+ if (!hidden || show_achievement_hidden_unearned) {
+
+ ImGui::Separator();
+
+ // Anchor the image to the right side of the list.
+ ImVec2 target = ImGui::GetCursorPos();
+ target.x = window_x_offset;
+ if (target.x > (256 * 0.4f)) {
+ target.x = target.x - (256 * 0.4f);
+ } else {
+ target.x = 0;
+ }
+
+ ImGui::PushTextWrapPos(target.x);
+ ImGui::Text("%s", x.title.c_str());
+ if (hidden) {
+ ImGui::Text("Hidden Achievement");
+ } else {
+ ImGui::Text("%s", x.description.c_str());
+ }
+ ImGui::PopTextWrapPos();
+
+ if (achieved) {
+ char buffer[80] = {};
+ time_t unlock_time = (time_t)x.unlock_time;
+ std::strftime(buffer, 80, "%Y-%m-%d at %H:%M:%S", std::localtime(&unlock_time));
+
+ ImGui::TextColored(ImVec4(0, 255, 0, 255), "achieved on %s", buffer);
+ } else {
+ ImGui::TextColored(ImVec4(255, 0, 0, 255), "not achieved");
+ }
+
+ // Set cursor for image output.
+ if (target.x != 0) {
+ ImGui::SetCursorPos(target);
+ }
+
+ display_imgui_achievement(256 * 0.4f, 256 * 0.4f,
+ 1.0f, 1.0f, 1.0f, 1.0f,
+ x.name);
+
+ ImGui::Separator();
+ }
+ }
+ ImGui::EndChild();
+ }
+ ImGui::End();
+ show_achievements = show;
+ }
+
}
if (show_settings) {
@@ -1374,41 +2541,530 @@ void Steam_Overlay::OverlayProc()
ImGui::Separator();
- ImGui::Text("Username:");
- ImGui::SameLine();
- ImGui::InputText("##username", username_text, sizeof(username_text), disable_forced ? ImGuiInputTextFlags_ReadOnly : 0);
+ {
+ std::lock_guard lock(overlay_mutex);
- ImGui::Separator();
+ ImGui::Text("Username:");
+ ImGui::SameLine();
+ ImGui::InputText("##username", username_text, sizeof(username_text), disable_forced ? ImGuiInputTextFlags_ReadOnly : 0);
- ImGui::Text("Language:");
+ ImGui::Separator();
- if (ImGui::ListBox("##language", ¤t_language, valid_languages, sizeof(valid_languages) / sizeof(char *), 7)) {
+ ImGui::Text("Language:");
- }
+ if (ImGui::ListBox("##language", ¤t_language, valid_languages, sizeof(valid_languages) / sizeof(char *), 7)) {
- ImGui::Text("Selected Language: %s", valid_languages[current_language]);
-
- ImGui::Separator();
-
- ImGui::Checkbox("Show achievement descriptions on unlock", &show_achievement_desc_on_unlock);
- ImGui::Checkbox("Show unearned hidden achievements", &show_achievement_hidden_unearned);
-
- ImGui::Separator();
-
- if (!disable_forced) {
- ImGui::Text("You may have to restart the game for these to apply.");
- if (ImGui::Button("Save")) {
- save_settings = true;
- show_settings = false;
}
- } else {
- ImGui::TextColored(ImVec4(255, 0, 0, 255), "WARNING WARNING WARNING");
- ImGui::TextWrapped("Some steam_settings/force_*.txt files have been detected. Please delete them if you want this menu to work.");
- ImGui::TextColored(ImVec4(255, 0, 0, 255), "WARNING WARNING WARNING");
+
+ ImGui::Text("Selected Language: %s", valid_languages[current_language]);
+
+ ImGui::Separator();
+
+ ImGui::LabelText("##notificationpositions", "Notification Positions");
+
+ if (ImGui::BeginListBox("##notificationpositions", ImVec2(-0.1f, ImGui::GetTextLineHeightWithSpacing() * 4.25f + currentStyle.FramePadding.y * 2.0f))) {
+ for (size_t x = 0; x < (sizeof(valid_ui_notification_position_labels) / sizeof(char*)); x++) {
+ bool sel = false;
+ sel = ImGui::Selectable(valid_ui_notification_position_labels[x],
+ (current_ui_notification_position_selection == x),
+ ImGuiSelectableFlags_AllowDoubleClick);
+ if (sel) {
+ PRINT_DEBUG("%s %s.\n",
+ "SteamOverlay::OverlayProc click on notification positions item",
+ valid_ui_notification_position_labels[x]);
+ switch (x) {
+ case 0:
+ notif_position = k_EPositionTopLeft;
+ current_ui_notification_position_selection = 0;
+ break;
+ case 1:
+ notif_position = k_EPositionTopRight;
+ current_ui_notification_position_selection = 1;
+ break;
+ case 2:
+ notif_position = k_EPositionBottomLeft;
+ current_ui_notification_position_selection = 2;
+ break;
+ case 3:
+ notif_position = k_EPositionBottomRight;
+ current_ui_notification_position_selection = 3;
+ break;
+ default:
+ break;
+ };
+ }
+ }
+
+ ImGui::EndListBox();
+ }
+
+ ImGui::Text("Selected notification position: %s", valid_ui_notification_position_labels[current_ui_notification_position_selection]);
+
+ ImGui::Separator();
+
+ ImGui::Checkbox("Show achievement descriptions on unlock", &show_achievement_desc_on_unlock);
+ ImGui::Checkbox("Show unearned hidden achievements", &show_achievement_hidden_unearned);
+
+ ImGui::Separator();
+
+ if (ImGui::Button("Set User Profile Image")) {
+ show_profile_image_select = true;
+ }
+
+ ImGui::Separator();
+
+ if (!disable_forced) {
+ ImGui::Text("You may have to restart the game for these to apply.");
+ if (ImGui::Button("Save")) {
+ save_settings = true;
+ show_settings = false;
+ show_profile_image_select = false;
+ }
+ } else {
+ ImGui::TextColored(ImVec4(255, 0, 0, 255), "WARNING WARNING WARNING");
+ ImGui::TextWrapped("Some steam_settings/force_*.txt files have been detected. Please delete them if you want this menu to work.");
+ ImGui::TextColored(ImVec4(255, 0, 0, 255), "WARNING WARNING WARNING");
+ }
}
}
ImGui::End();
+
+ if (show_profile_image_select) {
+ bool shown_drive_list = false;
+ {
+ std::lock_guard lock(overlay_mutex);
+
+ cleared_new_profile_images_struct = false;
+ shown_drive_list = show_drive_list;
+
+ if (shown_drive_list) {
+ std::vector temp = Local_Storage::get_drive_list();
+ for (auto x : temp) {
+ filesystem_list[x] = false;
+ }
+ } else {
+ if (current_path.length() <= 0) {
+ filesystem_list.clear();
+ if (future_path.length() > 0) {
+ current_path = future_path;
+ future_path.clear();
+ } else {
+ current_path = Local_Storage::get_user_pictures_path();
+ }
+ }
+
+ if (filesystem_list.size() <= 0) {
+ std::vector temp = Local_Storage::get_filenames_path(current_path);
+ for (auto x : temp) {
+ filesystem_list[x] = false;
+ }
+ filesystem_list[".."] = false;
+ }
+ }
+ }
+
+ if (ImGui::Begin("Set User Profile Image", &show_profile_image_select, ImGuiWindowFlags_AlwaysAutoResize)) {
+
+ std::string status_message = "";
+ bool small_image_displayed = false;
+ bool medium_image_displayed = false;
+ bool large_image_displayed = false;
+ user_image_displayed = false;
+ bool found_profile_images = false;
+
+ ImGui::Text("Currently Used Profile Images:");
+ small_image_displayed = (display_imgui_avatar(50.0f, 50.0f,
+ 1.0f, 1.0f, 1.0f, 1.0f,
+ local_user_id,
+ k_EAvatarSize32x32) == 1);
+ if (small_image_displayed == false) {
+ ImGui::ColorButton("test", ImVec4(255, 0, 0, 255), 0, ImVec2(50.0f, 50.0f));
+ }
+ ImGui::SameLine();
+
+ medium_image_displayed = (display_imgui_avatar(70.0f, 70.0f,
+ 1.0f, 1.0f, 1.0f, 1.0f,
+ local_user_id,
+ k_EAvatarSize64x64) == 1);
+ if (medium_image_displayed == false) {
+ ImGui::ColorButton("test", ImVec4(255, 0, 0, 255), 0, ImVec2(70.0f, 70.0f));
+ }
+ ImGui::SameLine();
+
+ large_image_displayed = (display_imgui_avatar(90.0f, 90.0f,
+ 1.0f, 1.0f, 1.0f, 1.0f,
+ local_user_id,
+ k_EAvatarSize184x184) == 1);
+ if (large_image_displayed == false) {
+ ImGui::ColorButton("test", ImVec4(255, 0, 0, 255), 0, ImVec2(90.0f, 90.0f));
+ }
+ ImGui::SameLine();
+ user_image_displayed = (small_image_displayed && medium_image_displayed && large_image_displayed);
+ ImGui::Separator();
+
+ ImGui::TextWrapped("Select image size to configure:");
+ ImGui::SameLine();
+
+ {
+ std::lock_guard lock(overlay_mutex);
+ if (ImGui::RadioButton("32x32 (Small)", (radio_btn_new_profile_image_size[0] == true)) == true) {
+ radio_btn_new_profile_image_size[0] = true;
+ radio_btn_new_profile_image_size[1] = false;
+ radio_btn_new_profile_image_size[2] = false;
+ }
+ ImGui::SameLine();
+ if (ImGui::RadioButton("64x64 (Medium)", (radio_btn_new_profile_image_size[1] == true)) == true) {
+ radio_btn_new_profile_image_size[1] = true;
+ radio_btn_new_profile_image_size[0] = false;
+ radio_btn_new_profile_image_size[2] = false;
+ }
+ ImGui::SameLine();
+ if (ImGui::RadioButton("184x184 (Large)", (radio_btn_new_profile_image_size[2] == true)) == true) {
+ radio_btn_new_profile_image_size[2] = true;
+ radio_btn_new_profile_image_size[0] = false;
+ radio_btn_new_profile_image_size[1] = false;
+ }
+ }
+ ImGui::TextWrapped("Note: Selected image must have a resolution bigger than the previous option and less than or equal to the selected option.");
+ ImGui::Separator();
+
+ bool load_image_file = false;
+ ImGui::TextWrapped("Please select a JPG or PNG file");
+ {
+ std::lock_guard lock(overlay_mutex);
+ if (new_profile_image_path.length() > 0) {
+ load_image_file = true;
+ }
+ std::string path_message = "Current Path: " + current_path;
+ ImGui::TextWrapped(path_message.c_str());
+ }
+ if (ImGui::Button("Up")) {
+ std::string temp = Local_Storage::get_parent_directory(current_path);
+ PRINT_DEBUG("%s\n", "SteamOverlay::OverlayProc Image Select Up button.");
+ if (Local_Storage::is_directory(temp) == true) {
+ PRINT_DEBUG("%s %s %s.\n", "SteamOverlay::OverlayProc ", temp.c_str(), " is a directory");
+ std::lock_guard lock(overlay_mutex);
+ current_path.clear();
+ future_path = temp;
+ show_drive_list = false;
+ } else {
+ PRINT_DEBUG("%s %s %s.\n", "SteamOverlay::OverlayProc ", temp.c_str(), " is NOT a directory");
+ }
+ }
+ ImGui::SameLine();
+ if (ImGui::Button("Home")) {
+ PRINT_DEBUG("%s.\n", "SteamOverlay::OverlayProc Image Select Home button");
+ std::lock_guard lock(overlay_mutex);
+ future_path = Local_Storage::get_user_pictures_path();
+ if (future_path.length() > 0) {
+ current_path.clear();
+ show_drive_list = false;
+ }
+ }
+ ImGui::SameLine();
+ if (ImGui::Button("Drives")) {
+ PRINT_DEBUG("%s.\n", "SteamOverlay::OverlayProc Image Select Drives button");
+ std::lock_guard lock(overlay_mutex);
+ show_drive_list = true;
+ current_path.clear();
+ future_path.clear();
+ filesystem_list.clear();
+ }
+ if (ImGui::BeginListBox("##FileSelect")) {
+ {
+ std::lock_guard lock(overlay_mutex);
+ for (auto x : filesystem_list) {
+ if (x.first.length() > 0) {
+ x.second = ImGui::Selectable(x.first.c_str(), x.second, ImGuiSelectableFlags_AllowDoubleClick);
+
+ if (x.second) {
+ PRINT_DEBUG("%s %s.\n", "SteamOverlay::OverlayProc click on filesystem list item", x.first.c_str());
+ if (shown_drive_list) {
+ future_path = ((x.first.find_last_of((char)PATH_SEPARATOR) == (x.first.length())) ? (x.first) : (x.first + PATH_SEPARATOR));
+ if (Local_Storage::is_directory(future_path) == true) {
+ current_path.clear();
+ show_drive_list = false;
+ PRINT_DEBUG("%s %s %"PRI_ZU" %"PRI_ZU".\n", "SteamOverlay::OverlayProc Next directory will be", future_path.c_str(), x.first.find_last_of((char)PATH_SEPARATOR), x.first.length());
+ } else {
+ future_path.clear();
+ }
+ } else {
+ if (x.first == "..") {
+ future_path = Local_Storage::get_parent_directory(current_path);
+ PRINT_DEBUG("%s %s is %s.\n", "SteamOverlay::OverlayProc parent directory of", current_path.c_str(), future_path.c_str());
+ if (Local_Storage::is_directory(future_path) == true) {
+ PRINT_DEBUG("%s %s %s.\n", "SteamOverlay::OverlayProc ", future_path.c_str(), "is a directory");
+ current_path.clear();
+ } else {
+ PRINT_DEBUG("%s %s %s.\n", "SteamOverlay::OverlayProc ", future_path.c_str(), "is NOT a directory");
+ future_path.clear();
+ }
+ } else {
+ std::string temp_path = ((x.first.find_last_of((char)PATH_SEPARATOR) == (x.first.length())) ? (current_path + x.first) : (current_path + PATH_SEPARATOR + x.first));
+ if (Local_Storage::is_directory(temp_path) == true) {
+ future_path = temp_path;
+ current_path.clear();
+ PRINT_DEBUG("%s %s.\n", "SteamOverlay::OverlayProc Next directory will be", future_path.c_str());
+ } else {
+ // Load file.
+ new_profile_image_path = temp_path;
+ status_message.clear();
+ tried_load_new_profile_image = false;
+ load_image_file = true;
+ PRINT_DEBUG("%s %s.\n", "SteamOverlay::OverlayProc Load file at", new_profile_image_path.c_str());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ ImGui::EndListBox();
+
+ ImGui::Separator();
+ }
+
+ if (load_image_file == true) {
+ Profile_Image image;
+ bool loaded_new_profile_image = false;
+ int new_image_size = k_EAvatarSizeMAX;
+ int new_image_pix_size_max = 0;
+ int new_image_pix_size_min = 0;
+ uint32_t new_profile_image_width = 0;
+ uint32_t new_profile_image_height = 0;
+ std::string image_path = "";
+ {
+ std::lock_guard lock(overlay_mutex);
+ if (radio_btn_new_profile_image_size[0]) {
+ new_image_size = k_EAvatarSize32x32;
+ new_image_pix_size_max = 32;
+ new_image_pix_size_min = 0;
+ image = new_profile_image_handles.small;
+ } else {
+ if (radio_btn_new_profile_image_size[1]) {
+ new_image_size = k_EAvatarSize64x64;
+ new_image_pix_size_max = 64;
+ new_image_pix_size_min = 32;
+ image = new_profile_image_handles.medium;
+ } else {
+ if (radio_btn_new_profile_image_size[2]) {
+ new_image_size = k_EAvatarSize184x184;
+ new_image_pix_size_max = 184;
+ new_image_pix_size_min = 64;
+ image = new_profile_image_handles.large;
+ } else {
+ new_image_size = k_EAvatarSizeMAX;
+ new_image_pix_size_max = 0;
+ new_image_pix_size_min = 0;
+ image = Profile_Image();
+ }
+ }
+ }
+ image_path = new_profile_image_path;
+ loaded_new_profile_image = tried_load_new_profile_image;
+ }
+
+ if (image_path.length() > 0 && new_image_size != k_EAvatarSizeMAX) {
+ if (loaded_new_profile_image == false) {
+ PRINT_DEBUG("%s\n", "SteamOverlay::OverlayProc New image load stage 1.");
+ {
+ std::lock_guard lock(overlay_mutex);
+ DestroyTemporaryImage(image.raw_image);
+ image.width = 0;
+ image.height = 0;
+ if (radio_btn_new_profile_image_size[0]) {
+ new_profile_image_handles.small = image;
+ } else {
+ if (radio_btn_new_profile_image_size[1]) {
+ new_profile_image_handles.medium = image;
+ } else {
+ if (radio_btn_new_profile_image_size[2]) {
+ new_profile_image_handles.large = image;
+ }
+ }
+ }
+ }
+
+ std::string new_profile_image_str = "";
+ PRINT_DEBUG("%s %s.\n", "SteamOverlay::OverlayProc Loading new image pixel data from", image_path.c_str());
+ new_profile_image_str = convert_vector_image_pixel_t_to_std_string(get_steam_client()->local_storage->load_image(image_path, &new_profile_image_width, &new_profile_image_height));
+ if ((new_profile_image_str.length() > 0) &&
+ (new_profile_image_width > new_image_pix_size_min) &&
+ (new_profile_image_width <= new_image_pix_size_max) &&
+ (new_profile_image_height > new_image_pix_size_min) &&
+ (new_profile_image_height <= new_image_pix_size_max)) {
+ uint8 * temp_raw_image = NULL;
+ temp_raw_image = new uint8[(new_profile_image_width * new_profile_image_height * sizeof(uint32_t))];
+ if (temp_raw_image != NULL) {
+ size_t y = 0;
+ for (auto & x : new_profile_image_str) {
+ if (y < new_profile_image_str.length() && y < (new_profile_image_width * new_profile_image_height * sizeof(uint32_t))) {
+ temp_raw_image[y] = x;
+ y++;
+ }
+ }
+ image.width = new_profile_image_width;
+ image.height = new_profile_image_height;
+ image.raw_image = temp_raw_image;
+
+ status_message = "Loaded selected image.\n";
+ ImGui::TextWrapped("Selected new avatar image:");
+ if (display_imgui_custom_image(50.0f, 50.0f,
+ 1.0f, 1.0f, 1.0f, 1.0f,
+ image.raw_image,
+ (image.width * image.height * sizeof(uint32_t)),
+ image.width,
+ image.height) == 1) {
+ std::lock_guard lock(overlay_mutex);
+ if (radio_btn_new_profile_image_size[0]) {
+ new_profile_image_handles.small = image;
+ } else {
+ if (radio_btn_new_profile_image_size[1]) {
+ new_profile_image_handles.medium = image;
+ } else {
+ if (radio_btn_new_profile_image_size[2]) {
+ new_profile_image_handles.large = image;
+ }
+ }
+ }
+ }
+
+ delete temp_raw_image;
+ temp_raw_image = NULL;
+ } else {
+ PRINT_DEBUG("%s\n", "SteamOverlay::OverlayProc Unable to allocate memory for new image.");
+ new_profile_image_str.clear();
+ new_profile_image_width = 0;
+ new_profile_image_height = 0;
+ }
+ } else {
+ PRINT_DEBUG("%s\n", "SteamOverlay::OverlayProc Unable to load new image. Invalid size, or invalid image.");
+ new_profile_image_str.clear();
+ new_profile_image_width = 0;
+ new_profile_image_height = 0;
+ status_message = "Failed to load selected image. Invalid size, or invalid image.\n";
+ }
+ {
+ std::lock_guard lock(overlay_mutex);
+ tried_load_new_profile_image = true;
+ }
+ } else {
+ PRINT_DEBUG("%s\n", "SteamOverlay::OverlayProc New image load stage 2.");
+ if (image.raw_image != NULL && image.width > 0 && image.height > 0) {
+ status_message = "Loaded selected image.\n";
+ ImGui::TextWrapped("Selected new avatar image:");
+ display_imgui_custom_image(50.0f, 50.0f,
+ 1.0f, 1.0f, 1.0f, 1.0f,
+ image.raw_image,
+ 0,
+ image.width,
+ image.height);
+ if (ImGui::Button("Apply")) {
+ Profile_Image temp_pi = GetTemporaryImage(image.raw_image);
+ if (temp_pi.raw_image != NULL && temp_pi.width > 0 && temp_pi.height > 0) {
+ Image_Data id;
+ //id.data = (char*)temp_pi.raw_image; Not a deep copy....
+ id.data.clear();
+ for (size_t x = 0; x < (temp_pi.width * temp_pi.height * sizeof(uint32_t)); x++) {
+ char a = (char)(temp_pi.raw_image[x]);
+ id.data += a;
+ }
+ id.width = temp_pi.width;
+ id.height = temp_pi.height;
+ PRINT_DEBUG("%s %d %s %"PRIu64".\n",
+ "SteamOverlay::OverlayProc Attempting to set new avatar image size",
+ new_image_size,
+ "for profile",
+ local_user_id.ConvertToUint64());
+ if (new_image_size == k_EAvatarSize32x32) {
+ std::lock_guard glock(global_mutex);
+ std::lock_guard lock(overlay_mutex);
+ if (settings->set_profile_image(k_EAvatarSize32x32, &id)) {
+ new_profile_image_path.clear();
+ save_small_profile_image = true;
+ show_profile_image_select = false;
+ } else {
+ status_message = "Failed to set active avatar image.\n";
+ }
+ }
+ if (new_image_size == k_EAvatarSize64x64) {
+ std::lock_guard glock(global_mutex);
+ std::lock_guard lock(overlay_mutex);
+ if (settings->set_profile_image(k_EAvatarSize64x64, &id)) {
+ new_profile_image_path.clear();
+ save_medium_profile_image = true;
+ show_profile_image_select = false;
+ } else {
+ status_message = "Failed to set active avatar image.\n";
+ }
+ }
+ if (new_image_size == k_EAvatarSize184x184) {
+ std::lock_guard glock(global_mutex);
+ std::lock_guard lock(overlay_mutex);
+ if (settings->set_profile_image(k_EAvatarSize184x184, &id)) {
+ new_profile_image_path.clear();
+ save_large_profile_image = true;
+ show_profile_image_select = false;
+ } else {
+ status_message = "Failed to set active avatar image.\n";
+ }
+ }
+ DestroyProfileImageResource(local_user_id, new_image_size);
+ DestroyProfileImage(local_user_id, new_image_size);
+ PRINT_DEBUG("%s\n", "Steam_Overlay::OverlayProc End apply new avatar image.");
+ } else {
+ PRINT_DEBUG("%s.\n",
+ "Steam_Overlay::OverlayProc Unable to set new avatar image. Image data expired");
+ status_message = "Loaded image data expired. Please reselect the image file in the file chooser above.";
+ }
+ ReturnTemporaryImage(temp_pi);
+ }
+ } else {
+ PRINT_DEBUG("%s\n", "SteamOverlay::OverlayProc Invalid image data after load cannot display.");
+ ImGui::TextColored(ImVec4(255, 0, 0, 255), "WARNING WARNING WARNING");
+ ImGui::TextWrapped("Could not load file as image. Image file must be either a PNG or JPG and must be less than or equal to selected resolution.");
+ ImGui::TextColored(ImVec4(255, 0, 0, 255), "WARNING WARNING WARNING");
+ status_message = "Selected file is not an image, or image has an invalid resolution.";
+ }
+ }
+ }
+ }
+ if (ImGui::Button("Cancel")) {
+ std::lock_guard lock(overlay_mutex);
+ show_profile_image_select = false;
+ }
+ ImGui::Separator();
+
+ ImGui::TextWrapped("Status");
+ ImGui::TextWrapped(status_message.c_str());
+ ImGui::Separator();
+
+ {
+ std::lock_guard lock(overlay_mutex);
+ current_status_message = status_message;
+ }
+ }
+
+ ImGui::End();
+ } else {
+ PRINT_DEBUG("%s\n", "SteamOverlay::OverlayProc Begin new avatar image select cleanup.");
+ std::lock_guard lock(overlay_mutex);
+ new_profile_image_path.clear();
+ new_profile_image_handles.small.raw_image = NULL; // Handle
+ new_profile_image_handles.small.width = 0;
+ new_profile_image_handles.small.height = 0;
+ new_profile_image_handles.medium.raw_image = NULL; // Handle
+ new_profile_image_handles.medium.width = 0;
+ new_profile_image_handles.medium.height = 0;
+ new_profile_image_handles.large.raw_image = NULL; // Handle
+ new_profile_image_handles.large.width = 0;
+ new_profile_image_handles.large.height = 0;
+ current_status_message.clear();
+ cleared_new_profile_images_struct = true;
+ PRINT_DEBUG("%s\n", "SteamOverlay::OverlayProc End new avatar image select cleanup.");
+ }
}
std::string url = show_url;
@@ -1484,7 +3140,8 @@ void Steam_Overlay::Callback(Common_Message *msg)
friend_info->second.window_state |= window_state_need_attention;
}
- AddMessageNotification(friend_info->first.name() + " says: " + steam_message.message());
+ AddMessageNotification(friend_info->first.name() + " says: " + steam_message.message(),
+ CSteamID((uint64)friend_info->first.id()));
NotifyUser(friend_info->second);
}
}
@@ -1554,6 +3211,83 @@ void Steam_Overlay::RunCallbacks()
PRINT_DEBUG("tried to start renderer %u\n", started);
}
+ if (Ready() && _renderer) {
+ bool done = false;
+ std::map