Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix some small problems with Device Selection Dialog #3851

Merged
Merged
1 change: 1 addition & 0 deletions Client/multiplayer_sa/CMultiplayerSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1574,6 +1574,7 @@ void CMultiplayerSA::InitHooks()
MemSet((void*)0x6C4453, 0x90, 0x68);

InitHooks_CrashFixHacks();
InitHooks_DeviceSelection();

// Init our 1.3 hooks.
Init_13();
Expand Down
1 change: 1 addition & 0 deletions Client/multiplayer_sa/CMultiplayerSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ class CMultiplayerSA : public CMultiplayer
void InitHooks_ProjectileCollisionFix();
void InitHooks_ObjectStreamerOptimization();
void InitHooks_Postprocess();
void InitHooks_DeviceSelection();
CRemoteDataStorage* CreateRemoteDataStorage();
void DestroyRemoteDataStorage(CRemoteDataStorage* pData);
void AddRemoteDataStorage(CPlayerPed* pPed, CRemoteDataStorage* pData);
Expand Down
155 changes: 155 additions & 0 deletions Client/multiplayer_sa/CMultiplayerSA_DeviceSelection.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
/*****************************************************************************
*
* PROJECT: Multi Theft Auto v1.0
* LICENSE: See LICENSE in the top level directory
* FILE: multiplayer_sa/CMultiplayerSA_DeviceSelection.cpp
*
* Multi Theft Auto is available from http://www.multitheftauto.com/
*
*****************************************************************************/

#include "StdInc.h"
#define FUNC_rwDeviceSystemRequest 0x7F2AB0
#define FUNC_DialogFunc 0x745E50
#define FUNC_RwEngineGetSubSystemInfo 0x7F2C30
#define CLASS_RwGlobals 0xC97B24
#define CLASS_IDirect3D9 0xC97C20
#define NUM_DialogFuncStackPushAddress 0x746239

// This is copied from SilentPatch:
// https://github.com/CookiePLMonster/SilentPatch/blob/dev/SilentPatch/FriendlyMonitorNames.cpp
std::unordered_map<std::string, std::string> GetFriendlyMonitorNamesForDevicePaths()
{
std::unordered_map<std::string, std::string> monitorNames;

HMODULE user32Lib = LoadLibrary(TEXT("user32"));
if (!user32Lib)
return monitorNames;

auto* getDisplayConfigBufferSizes = (decltype(GetDisplayConfigBufferSizes)*)GetProcAddress(user32Lib, "GetDisplayConfigBufferSizes");
auto* queryDisplayConfig = (decltype(QueryDisplayConfig)*)GetProcAddress(user32Lib, "QueryDisplayConfig");
auto* displayConfigGetDeviceInfo = (decltype(DisplayConfigGetDeviceInfo)*)GetProcAddress(user32Lib, "DisplayConfigGetDeviceInfo");
if (!getDisplayConfigBufferSizes || !queryDisplayConfig || !displayConfigGetDeviceInfo)
{
FreeLibrary(user32Lib);
return monitorNames;
}

UINT32 pathCount, modeCount;
std::unique_ptr<DISPLAYCONFIG_PATH_INFO[]> paths;
std::unique_ptr<DISPLAYCONFIG_MODE_INFO[]> modes;

LONG result = ERROR_SUCCESS;
do
{
result = getDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &pathCount, &modeCount);
if (result != ERROR_SUCCESS)
{
break;
}
paths = std::make_unique<DISPLAYCONFIG_PATH_INFO[]>(pathCount);
modes = std::make_unique<DISPLAYCONFIG_MODE_INFO[]>(modeCount);
result = queryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &pathCount, paths.get(), &modeCount, modes.get(), nullptr);
} while (result == ERROR_INSUFFICIENT_BUFFER);

if (result != ERROR_SUCCESS)
{
FreeLibrary(user32Lib);
return monitorNames;
}

for (size_t i = 0; i < pathCount; i++)
{
DISPLAYCONFIG_TARGET_DEVICE_NAME targetName = {};
targetName.header.adapterId = paths[i].targetInfo.adapterId;
targetName.header.id = paths[i].targetInfo.id;
targetName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
targetName.header.size = sizeof(targetName);
const LONG targetNameResult = DisplayConfigGetDeviceInfo(&targetName.header);

DISPLAYCONFIG_SOURCE_DEVICE_NAME sourceName = {};
sourceName.header.adapterId = paths[i].sourceInfo.adapterId;
sourceName.header.id = paths[i].sourceInfo.id;
sourceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
sourceName.header.size = sizeof(sourceName);
const LONG sourceNameResult = DisplayConfigGetDeviceInfo(&sourceName.header);
if (targetNameResult == ERROR_SUCCESS && sourceNameResult == ERROR_SUCCESS && targetName.monitorFriendlyDeviceName[0] != '\0')
{
char gdiDeviceName[std::size(sourceName.viewGdiDeviceName)];
char monitorFriendlyDeviceName[std::size(targetName.monitorFriendlyDeviceName)];
WideCharToMultiByte(CP_ACP, 0, sourceName.viewGdiDeviceName, -1, gdiDeviceName, static_cast<int>(std::size(gdiDeviceName)), nullptr, nullptr);
WideCharToMultiByte(CP_ACP, 0, targetName.monitorFriendlyDeviceName, -1, monitorFriendlyDeviceName,
static_cast<int>(std::size(monitorFriendlyDeviceName)), nullptr, nullptr);

monitorNames.try_emplace(gdiDeviceName, monitorFriendlyDeviceName);
}
}

FreeLibrary(user32Lib);
return monitorNames;
}

struct RwSubSystemInfo
{
char name[80];
};

using rwDeviceSystemRequest = RwSubSystemInfo*(__cdecl*)(RwDevice* device, std::int32_t requestId, RwSubSystemInfo* pOut, void* pInOut, std::int32_t numIn);
static RwSubSystemInfo* RwEngineGetSubSystemInfo_Hooked(RwSubSystemInfo* subSystemInfo, std::int32_t subSystemIndex)
{
auto* rwGlobals = *(RwGlobals**)CLASS_RwGlobals;
auto* rwDeviceSystemRequestFunc = (rwDeviceSystemRequest)(FUNC_rwDeviceSystemRequest);
if (!rwDeviceSystemRequestFunc(&rwGlobals->dOpenDevice, 14, subSystemInfo, nullptr, subSystemIndex))
return nullptr;

auto* pDxDevice = *(IDirect3D9**)CLASS_IDirect3D9;
if (!pDxDevice)
return subSystemInfo;

D3DADAPTER_IDENTIFIER9 identifier;
if (FAILED(pDxDevice->GetAdapterIdentifier(subSystemIndex, 0, &identifier)))
return subSystemInfo;

static const auto friendlyNames = GetFriendlyMonitorNamesForDevicePaths();

// If we can't find the friendly name, either because it doesn't exist or we're on an ancient Windows, fall back to the device name
auto it = friendlyNames.find(identifier.DeviceName);
if (it != friendlyNames.end())
{
strncpy_s(subSystemInfo->name, it->second.c_str(), _TRUNCATE);
}
else
{
strncpy_s(subSystemInfo->name, identifier.Description, _TRUNCATE);
}
forkerer marked this conversation as resolved.
Show resolved Hide resolved

return subSystemInfo;
}

INT_PTR CALLBACK CustomDlgProc(HWND window, UINT msg, WPARAM wParam, LPARAM lParam)
{
auto* orgDialogFunc = (DLGPROC)FUNC_DialogFunc;
if (msg != WM_INITDIALOG)
return orgDialogFunc(window, msg, wParam, lParam);

orgDialogFunc(window, msg, wParam, lParam);

// Set Icon
HMODULE hGameModule = GetModuleHandle(nullptr);
SendMessage(window, WM_SETICON, ICON_SMALL, reinterpret_cast<LPARAM>(LoadIcon(hGameModule, MAKEINTRESOURCE(100))));

// Make the dialog visible in the task bar
// https://stackoverflow.com/a/1462811
SetWindowLongPtr(window, GWL_EXSTYLE, WS_EX_APPWINDOW);
ShowWindow(window, SW_HIDE);
ShowWindow(window, SW_SHOW);
return FALSE;
}

void CMultiplayerSA::InitHooks_DeviceSelection()
{
// 0x746239 -> Exact address where the original DialogFunc address is being pushed as an argument to DialogBoxParamA(),
// we're replacing it with out own proxy function
MemPut<DLGPROC>(NUM_DialogFuncStackPushAddress, (DLGPROC)&CustomDlgProc);
HookInstall(FUNC_RwEngineGetSubSystemInfo, (DWORD)RwEngineGetSubSystemInfo_Hooked, 6);
}
46 changes: 46 additions & 0 deletions Client/sdk/game/RenderWare.h
Original file line number Diff line number Diff line change
Expand Up @@ -526,3 +526,49 @@ struct RwError
{
int err1, err2;
};

/*****************************************************************************/
/** RenderWare Globals **/
/*****************************************************************************/

typedef bool (*RwSystemFunc)(std::int32_t, void*, void*, std::int32_t);
forkerer marked this conversation as resolved.
Show resolved Hide resolved
struct RwDevice
{
float gammaCorrection;
RwSystemFunc fpSystem;
float zBufferNear;
float zBufferFar;
// RwRenderStateSetFunction fpRenderStateSet;
// RwRenderStateGetFunction fpRenderStateGet;
// RwIm2DRenderLineFunction fpIm2DRenderLine;
// RwIm2DRenderTriangleFunction fpIm2DRenderTriangle;
// RwIm2DRenderPrimitiveFunction fpIm2DRenderPrimitive;
// RwIm2DRenderIndexedPrimitiveFunction fpIm2DRenderIndexedPrimitive;
// RwIm3DRenderLineFunction fpIm3DRenderLine;
// RwIm3DRenderTriangleFunction fpIm3DRenderTriangle;
// RwIm3DRenderPrimitiveFunction fpIm3DRenderPrimitive;
// RwIm3DRenderIndexedPrimitiveFunction fpIm3DRenderIndexedPrimitive;
};
// static_assert(sizeof(RwDevice) == 0x38, "Incorrect class size: RwDevice");

typedef bool (*RwStandardFunc)(void*, void*, std::int32_t);
forkerer marked this conversation as resolved.
Show resolved Hide resolved
struct RwGlobals
{
void* curCamera;
void* curWorld;
std::uint16_t renderFrame;
std::uint16_t lightFrame;
std::uint16_t pad[2];
RwDevice dOpenDevice;
RwStandardFunc stdFunc[29];
// RwLinkList dirtyFrameList;
// RwFileFunctions fileFuncs;
// RwStringFunctions stringFuncs;
// RwMemoryFunctions memoryFuncs;
// RwMemoryAllocFn memoryAlloc;
// RwMemoryFreeFn memoryFree;
// RwMetrics* metrics;
// RwEngineStatus engineStatus;
// RwUInt32 resArenaInitSize;
};
//static_assert(sizeof(RwGlobals) == 0x158, "Incorrect class size: RwGlobals");
Loading