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
157 changes: 157 additions & 0 deletions Client/multiplayer_sa/CMultiplayerSA_DeviceSelection.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/*****************************************************************************
*
* 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"

// This is copied from SilentPatch:
// https://github.com/CookiePLMonster/SilentPatch/blob/dev/SilentPatch/FriendlyMonitorNames.cpp
std::map<std::string, std::string, std::less<>> GetFriendlyMonitorNamesForDevicePaths()
{
std::map<std::string, std::string, std::less<>> monitorNames;
forkerer marked this conversation as resolved.
Show resolved Hide resolved

#if WINVER < _WIN32_WINNT_WIN7
return monitorNames;
#else
forkerer marked this conversation as resolved.
Show resolved Hide resolved
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;
#endif
}

struct RwSubSystemInfo
{
char name[80];
};

#define FUNC_rwDeviceSystemRequest 0x7F2AB0
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**)(0xC97B24);
forkerer marked this conversation as resolved.
Show resolved Hide resolved
auto rwDeviceSystemRequestFunc = (rwDeviceSystemRequest)(FUNC_rwDeviceSystemRequest);
auto result = rwDeviceSystemRequestFunc(&rwGlobals->dOpenDevice, 14, subSystemInfo, nullptr, subSystemIndex);
if (!result)
return nullptr;
forkerer marked this conversation as resolved.
Show resolved Hide resolved

auto pDxDevice = *(IDirect3D9**)0xC97C20;
forkerer marked this conversation as resolved.
Show resolved Hide resolved
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;
}

#define FUNC_DialogFunc 0x745E50
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;
}

#define FUNC_RwEngineGetSubSystemInfo 0x7F2C30
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>(0x746239, (DLGPROC)&CustomDlgProc);
forkerer marked this conversation as resolved.
Show resolved Hide resolved
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