Skip to content

Commit 897a245

Browse files
Fix callbacks for pre-1.02x SDKs
1 parent 250ead8 commit 897a245

File tree

4 files changed

+112
-8
lines changed

4 files changed

+112
-8
lines changed

dll/dll.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,13 @@ Steam_Client *get_steam_client()
235235
if (!steamclient_instance) {
236236
load_old_steam_interfaces();
237237
steamclient_instance = new Steam_Client();
238+
239+
if (strstr(old_friends, "SteamFriends")) {
240+
int friends_ver = atoi(old_friends + 12);
241+
if (friends_ver != 0 && friends_ver <= 4) {
242+
steamclient_instance->using_old_callbacks = true;
243+
}
244+
}
238245
}
239246
}
240247

dll/dll/callback_wrapper.h

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/* Copyright (C) 2019 Mr Goldberg
2+
This file is part of the Goldberg Emulator
3+
4+
The Goldberg Emulator is free software; you can redistribute it and/or
5+
modify it under the terms of the GNU Lesser General Public
6+
License as published by the Free Software Foundation; either
7+
version 3 of the License, or (at your option) any later version.
8+
9+
The Goldberg Emulator is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+
Lesser General Public License for more details.
13+
14+
You should have received a copy of the GNU Lesser General Public
15+
License along with the Goldberg Emulator; if not, see
16+
<http://www.gnu.org/licenses/>. */
17+
18+
#ifndef __INCLUDED_CALLBACK_WRAPPER_H__
19+
#define __INCLUDED_CALLBACK_WRAPPER_H__
20+
21+
#include "base.h"
22+
23+
class CCallbackBase001
24+
{
25+
public:
26+
CCallbackBase001() { m_nCallbackFlags = 0; m_iCallback = 0; }
27+
// don't add a virtual destructor because we export this binary interface across dll's
28+
virtual void Run( void *pvParam ) = 0;
29+
int GetICallback() { return m_iCallback; }
30+
31+
protected:
32+
enum { k_ECallbackFlagsRegistered = 0x01, k_ECallbackFlagsGameServer = 0x02 };
33+
uint8 m_nCallbackFlags;
34+
int m_iCallback;
35+
friend class CCallbackMgr;
36+
friend class CCallBackWrapper;
37+
38+
private:
39+
CCallbackBase001( const CCallbackBase001& );
40+
CCallbackBase001& operator=( const CCallbackBase001& );
41+
};
42+
43+
class CCallBackWrapper : public CCallbackBase
44+
{
45+
public:
46+
CCallBackWrapper( CCallbackBase *callback )
47+
{
48+
old_callback = reinterpret_cast<CCallbackBase001 *>( callback );
49+
m_nCallbackFlags = old_callback->m_nCallbackFlags;
50+
m_iCallback = old_callback->m_iCallback;
51+
}
52+
53+
void Run( void *pvParam )
54+
{
55+
old_callback->Run( pvParam );
56+
}
57+
void Run( void *pvParam, bool bIOFailure, SteamAPICall_t hSteamAPICall )
58+
{
59+
old_callback->Run( pvParam );
60+
}
61+
int GetCallbackSizeBytes()
62+
{
63+
return 0;
64+
}
65+
66+
private:
67+
CCallbackBase001 *old_callback{};
68+
};
69+
70+
#endif // __INCLUDED_CALLBACK_WRAPPER_H__

dll/dll/steam_client.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464

6565
#include "overlay/steam_overlay.h"
6666
#include "playtime.h"
67+
#include "callback_wrapper.h"
6768

6869
enum Steam_Pipe {
6970
NO_USER,
@@ -111,6 +112,8 @@ public ISteamClient
111112
common_helpers::KillableWorker *background_thread{};
112113
void background_thread_proc();
113114

115+
std::map<CCallbackBase *, CCallBackWrapper> old_callbacks_map;
116+
114117
public:
115118
Networking *network{};
116119
SteamCallResults *callback_results_server{}, *callback_results_client{};
@@ -180,10 +183,11 @@ public ISteamClient
180183

181184
PlaytimeCounter* playtime_counter{};
182185

183-
bool steamclient_server_inited = false;
186+
bool steamclient_server_inited{};
184187

185188
bool gameserver_has_ipv6_functions{};
186189
int steamclient_version{};
190+
bool using_old_callbacks{};
187191

188192
unsigned steam_pipe_counter = 1;
189193
std::map<HSteamPipe, enum Steam_Pipe> steam_pipes{};

dll/steam_client.cpp

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -484,9 +484,20 @@ void Steam_Client::Remove_SteamAPI_CPostAPIResultInProcess( SteamAPI_PostAPIResu
484484

485485
void Steam_Client::RegisterCallback( class CCallbackBase *pCallback, int iCallback)
486486
{
487+
CCallbackBase *callback_to_add = pCallback;
488+
489+
// 1.02x added an overload for CCallbackBase::Run. Because of how MSVC handles virtual function
490+
// overloads, this changed the order of functions in vtable from 1.02, which breaks old games.
491+
// We get around this using a wrapper for the old CCallbackBase variant.
492+
if (using_old_callbacks) {
493+
PRINT_DEBUG("creating a wrapper for old callback %08X %i", pCallback, iCallback);
494+
auto [it, _] = old_callbacks_map.emplace(pCallback, pCallback);
495+
callback_to_add = &(it->second);
496+
}
497+
487498
int base_callback = (iCallback / 100) * 100;
488499
int callback_id = iCallback % 100;
489-
bool isGameServer = CCallbackMgr::isServer(pCallback);
500+
bool isGameServer = CCallbackMgr::isServer(callback_to_add);
490501
PRINT_DEBUG("isGameServer %u %i %i", isGameServer, iCallback, base_callback);
491502

492503
switch (base_callback) {
@@ -699,18 +710,26 @@ void Steam_Client::RegisterCallback( class CCallbackBase *pCallback, int iCallba
699710
};
700711

701712
if (isGameServer) {
702-
callbacks_server->addCallBack(iCallback, pCallback);
713+
callbacks_server->addCallBack(iCallback, callback_to_add);
703714
} else {
704-
callbacks_client->addCallBack(iCallback, pCallback);
715+
callbacks_client->addCallBack(iCallback, callback_to_add);
705716
}
706717
}
707718

708719
void Steam_Client::UnregisterCallback( class CCallbackBase *pCallback)
709720
{
710-
int iCallback = pCallback->GetICallback();
721+
CCallbackBase *callback_to_rm = pCallback;
722+
if (using_old_callbacks) {
723+
if (!old_callbacks_map.count(pCallback))
724+
return;
725+
726+
callback_to_rm = &(old_callbacks_map.at(pCallback));
727+
}
728+
729+
int iCallback = callback_to_rm->GetICallback();
711730
int base_callback = (iCallback / 100) * 100;
712731
int callback_id = iCallback % 100;
713-
bool isGameServer = CCallbackMgr::isServer(pCallback);
732+
bool isGameServer = CCallbackMgr::isServer(callback_to_rm);
714733
PRINT_DEBUG("isGameServer %u %i", isGameServer, base_callback);
715734

716735
switch (base_callback) {
@@ -923,9 +942,13 @@ void Steam_Client::UnregisterCallback( class CCallbackBase *pCallback)
923942
};
924943

925944
if (isGameServer) {
926-
callbacks_server->rmCallBack(iCallback, pCallback);
945+
callbacks_server->rmCallBack(iCallback, callback_to_rm);
927946
} else {
928-
callbacks_client->rmCallBack(iCallback, pCallback);
947+
callbacks_client->rmCallBack(iCallback, callback_to_rm);
948+
}
949+
950+
if (using_old_callbacks) {
951+
old_callbacks_map.erase(pCallback);
929952
}
930953
}
931954

0 commit comments

Comments
 (0)