Skip to content

Commit d131061

Browse files
committed
Axis&Allies, 102Dalmatians and 18WheelsOfSteelAcrossAmerica:
- Improved the fixes' structure by creating a base class (FixBase.hpp) for common functionalities, reducing code duplication and enhancing maintainability.
1 parent e3d9e44 commit d131061

5 files changed

Lines changed: 183 additions & 418 deletions

File tree

‎project/Axis&AlliesFOVFix.vcxproj‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
7575
<TargetExt>.asi</TargetExt>
7676
<IncludePath>..\external\inipp;..\external\safetyhook;..\external\spdlog\include;..\includes;$(IncludePath)</IncludePath>
77+
<ExternalIncludePath>$(ExternalIncludePath)</ExternalIncludePath>
7778
</PropertyGroup>
7879
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
7980
<TargetExt>.asi</TargetExt>
@@ -110,6 +111,7 @@
110111
<Optimization>Disabled</Optimization>
111112
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
112113
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
114+
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
113115
</ClCompile>
114116
<Link>
115117
<SubSystem>Console</SubSystem>

‎source/common/FixBase.hpp‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
#include <string>
1717
#include <cstdint>
1818

19+
#define spdlog_confparse(var) spdlog::info("Config Parse: {}: {}", #var, var)
20+
1921
class FixBase
2022
{
2123
public:
@@ -155,6 +157,18 @@ class FixBase
155157

156158
bool enabled_ = true;
157159

160+
virtual void FallbackToDesktopResolution(int& width, int& height)
161+
{
162+
if (width <= 0 || height <= 0)
163+
{
164+
spdlog::info("Resolution not specified in ini file. Using desktop resolution.");
165+
166+
auto desktopDimensions = Util::GetPhysicalDesktopDimensions();
167+
width = desktopDimensions.first;
168+
height = desktopDimensions.second;
169+
}
170+
}
171+
158172
private:
159173
static DWORD WINAPI ThreadProc(LPVOID param)
160174
{
Lines changed: 75 additions & 202 deletions
Original file line numberDiff line numberDiff line change
@@ -1,245 +1,118 @@
1-
// Include necessary headers
2-
#include "stdafx.h"
3-
#include "helper.hpp"
4-
5-
#include <spdlog/spdlog.h>
6-
#include <spdlog/sinks/basic_file_sink.h>
7-
#include <inipp/inipp.h>
8-
#include <safetyhook.hpp>
9-
#include <vector>
10-
#include <map>
11-
#include <windows.h>
12-
#include <psapi.h> // For GetModuleInformation
13-
#include <fstream>
14-
#include <filesystem>
15-
#include <sstream>
16-
#include <cstring>
17-
#include <iomanip>
18-
#include <cstdint>
19-
#include <iostream>
20-
21-
#define spdlog_confparse(var) spdlog::info("Config Parse: {}: {}", #var, var)
22-
23-
HMODULE exeModule = GetModuleHandle(NULL);
24-
HMODULE dllModule = nullptr;
25-
HMODULE thisModule;
26-
27-
// Fix details
28-
std::string sFixName = "102DalmatiansPuppiesToTheRescueFOVFix";
29-
std::string sFixVersion = "1.0";
30-
std::filesystem::path sFixPath;
31-
32-
// Ini
33-
inipp::Ini<char> ini;
34-
std::string sConfigFile = sFixName + ".ini";
35-
36-
// Logger
37-
std::shared_ptr<spdlog::logger> logger;
38-
std::string sLogFile = sFixName + ".log";
39-
std::filesystem::path sExePath;
40-
std::string sExeName;
41-
42-
// Constants
43-
constexpr float fOldAspectRatio = 4.0f / 3.0f;
44-
constexpr uint16_t iOriginalCameraHFOV = 4096;
45-
46-
// Ini variables
47-
bool bFixActive;
48-
int iCurrentResX;
49-
int iCurrentResY;
50-
51-
// Variables
52-
float fNewAspectRatio;
53-
float fAspectRatioScale;
54-
uint16_t iNewCameraHFOV;
55-
56-
// Game detection
57-
enum class Game
58-
{
59-
DPTTR,
60-
Unknown
61-
};
1+
#include "..\..\common\FixBase.hpp"
622

63-
struct GameInfo
3+
class DalmatiansFix final : public FixBase
644
{
65-
std::string GameTitle;
66-
std::string ExeName;
67-
};
68-
69-
const std::map<Game, GameInfo> kGames = {
70-
{Game::DPTTR, {"102 Dalmatians: Puppies to the Rescue", "Pcdogs.exe"}},
71-
};
72-
73-
const GameInfo* game = nullptr;
74-
Game eGameType = Game::Unknown;
75-
76-
void Logging()
77-
{
78-
// Get path to DLL
79-
WCHAR dllPath[_MAX_PATH] = { 0 };
80-
GetModuleFileNameW(thisModule, dllPath, MAX_PATH);
81-
sFixPath = dllPath;
82-
sFixPath = sFixPath.remove_filename();
83-
84-
// Get game name and exe path
85-
WCHAR exePathW[_MAX_PATH] = { 0 };
86-
GetModuleFileNameW(dllModule, exePathW, MAX_PATH);
87-
sExePath = exePathW;
88-
sExeName = sExePath.filename().string();
89-
sExePath = sExePath.remove_filename();
90-
91-
// Spdlog initialization
92-
try
5+
public:
6+
explicit DalmatiansFix(HMODULE selfModule) : FixBase(selfModule)
937
{
94-
logger = spdlog::basic_logger_st(sFixName.c_str(), sExePath.string() + "\\" + sLogFile, true);
95-
spdlog::set_default_logger(logger);
96-
spdlog::flush_on(spdlog::level::debug);
97-
spdlog::set_level(spdlog::level::debug); // Enable debug level logging
98-
99-
spdlog::info("----------");
100-
spdlog::info("{:s} v{:s} loaded.", sFixName.c_str(), sFixVersion.c_str());
101-
spdlog::info("----------");
102-
spdlog::info("Log file: {}", sExePath.string() + "\\" + sLogFile);
103-
spdlog::info("----------");
104-
spdlog::info("Module Name: {0:s}", sExeName.c_str());
105-
spdlog::info("Module Path: {0:s}", sExePath.string());
106-
spdlog::info("Module Address: 0x{0:X}", (uintptr_t)dllModule);
107-
spdlog::info("----------");
108-
spdlog::info("DLL has been successfully loaded.");
8+
s_instance_ = this;
1099
}
110-
catch (const spdlog::spdlog_ex& ex)
10+
11+
~DalmatiansFix() override
11112
{
112-
AllocConsole();
113-
FILE* dummy;
114-
freopen_s(&dummy, "CONOUT$", "w", stdout);
115-
std::cout << "Log initialization failed: " << ex.what() << std::endl;
116-
FreeLibraryAndExitThread(thisModule, 1);
13+
if (s_instance_ == this)
14+
{
15+
s_instance_ = nullptr;
16+
}
11717
}
118-
}
11918

120-
void Configuration()
121-
{
122-
// Inipp initialization
123-
std::ifstream iniFile(sFixPath.string() + "\\" + sConfigFile);
124-
if (!iniFile)
19+
protected:
20+
const char* FixName() const override
12521
{
126-
AllocConsole();
127-
FILE* dummy;
128-
freopen_s(&dummy, "CONOUT$", "w", stdout);
129-
std::cout << sFixName.c_str() << " v" << sFixVersion.c_str() << " loaded." << std::endl;
130-
std::cout << "ERROR: Could not locate config file." << std::endl;
131-
std::cout << "ERROR: Make sure " << sConfigFile.c_str() << " is located in " << sFixPath.string().c_str() << std::endl;
132-
spdlog::shutdown();
133-
FreeLibraryAndExitThread(thisModule, 1);
22+
return "102DalmatiansPuppiesToTheRescueFOVFix";
13423
}
135-
else
24+
25+
const char* FixVersion() const override
13626
{
137-
spdlog::info("Config file: {}", sFixPath.string() + "\\" + sConfigFile);
138-
ini.parse(iniFile);
27+
return "1.1";
13928
}
14029

141-
// Parse config
142-
ini.strip_trailing_comments();
143-
spdlog::info("----------");
144-
145-
// Load settings from ini
146-
inipp::get_value(ini.sections["FOVFix"], "Enabled", bFixActive);
147-
spdlog_confparse(bFixActive);
148-
149-
// Load resolution from ini
150-
inipp::get_value(ini.sections["Settings"], "Width", iCurrentResX);
151-
inipp::get_value(ini.sections["Settings"], "Height", iCurrentResY);
152-
spdlog_confparse(iCurrentResX);
153-
spdlog_confparse(iCurrentResY);
154-
155-
// If resolution not specified, use desktop resolution
156-
if (iCurrentResX <= 0 || iCurrentResY <= 0)
30+
const char* TargetName() const override
15731
{
158-
spdlog::info("Resolution not specified in ini file. Using desktop resolution.");
159-
// Implement Util::GetPhysicalDesktopDimensions() accordingly
160-
auto desktopDimensions = Util::GetPhysicalDesktopDimensions();
161-
iCurrentResX = desktopDimensions.first;
162-
iCurrentResY = desktopDimensions.second;
163-
spdlog_confparse(iCurrentResX);
164-
spdlog_confparse(iCurrentResY);
32+
return "102 Dalmatians: Puppies to the Rescue";
16533
}
16634

167-
spdlog::info("----------");
168-
}
169-
170-
bool DetectGame()
171-
{
172-
for (const auto& [type, info] : kGames)
35+
InitMode GetInitMode() const override
17336
{
174-
if (Util::stringcmp_caseless(info.ExeName, sExeName))
175-
{
176-
spdlog::info("Detected game: {:s} ({:s})", info.GameTitle, sExeName);
177-
spdlog::info("----------");
178-
eGameType = type;
179-
game = &info;
180-
return true;
181-
}
37+
// return InitMode::Direct;
38+
return InitMode::WorkerThread;
39+
// return InitMode::ExportedOnly;
18240
}
18341

184-
spdlog::error("Failed to detect supported game, {:s} isn't supported by the fix.", sExeName);
185-
return false;
186-
}
42+
bool IsCompatibleExecutable(const std::string& exeName) const override
43+
{
44+
return Util::stringcmp_caseless(exeName, "Pcdogs.exe");
45+
}
18746

188-
void FOVFix()
189-
{
190-
if (eGameType == Game::DPTTR && bFixActive == true)
47+
void ParseFixConfig(inipp::Ini<char>& ini) override
19148
{
192-
fNewAspectRatio = static_cast<float>(iCurrentResX) / static_cast<float>(iCurrentResY);
49+
inipp::get_value(ini.sections["Settings"], "Width", m_newResX);
50+
inipp::get_value(ini.sections["Settings"], "Height", m_newResY);
19351

194-
fAspectRatioScale = fNewAspectRatio / fOldAspectRatio;
52+
FallbackToDesktopResolution(m_newResX, m_newResY);
19553

196-
std::uint8_t* AspectRatioInstructionScanResult = Memory::PatternScan(exeModule, "0D 00 00 00 0F 00 00 00 10 00 00 00 FF 00 00 00 00 10 00 00 00 00 00 00 00 10 00 00 00");
197-
if (AspectRatioInstructionScanResult)
198-
{
199-
spdlog::info("Aspect Ratio Instruction: Address is {:s}+{:x}", sExeName.c_str(), AspectRatioInstructionScanResult + 16 - (std::uint8_t*)exeModule);
54+
spdlog_confparse(m_newResX);
55+
spdlog_confparse(m_newResY);
56+
}
20057

201-
iNewCameraHFOV = (int)(iOriginalCameraHFOV / fAspectRatioScale);
58+
void ApplyFix() override
59+
{
60+
m_newAspectRatio = static_cast<float>(m_newResX) / static_cast<float>(m_newResY);
61+
m_aspectRatioScale = m_newAspectRatio / m_oldAspectRatio;
20262

203-
Memory::Write(AspectRatioInstructionScanResult + 16, iNewCameraHFOV);
204-
}
205-
else
63+
auto AspectRatioScanResult = Memory::PatternScan(ExeModule(), "0D 00 00 00 0F 00 00 00 10 00 00 00 FF 00 00 00 00 10 00 00 00 00 00 00 00 10 00 00 00");
64+
if (!AspectRatioScanResult)
20665
{
207-
spdlog::error("Failed to locate aspect ratio instruction memory address.");
66+
spdlog::error("Failed to locate aspect ratio memory address.");
20867
return;
20968
}
210-
}
211-
}
21269

213-
DWORD __stdcall Main(void*)
214-
{
215-
Logging();
216-
Configuration();
217-
if (DetectGame())
218-
{
219-
FOVFix();
70+
spdlog::info("Aspect Ratio: Address is {}+{:x}", ExeName().c_str(), AspectRatioScanResult + 16 - reinterpret_cast<std::uint8_t*>(ExeModule()));
71+
72+
iNewAspectRatio = (int)(iOriginalAspectRatio / m_aspectRatioScale);
73+
74+
Memory::Write(AspectRatioScanResult + 16, iNewAspectRatio);
22075
}
221-
return TRUE;
222-
}
76+
77+
private:
78+
static constexpr float m_oldAspectRatio = 4.0f / 3.0f;
79+
static constexpr uint16_t iOriginalAspectRatio = 4096;
80+
static inline int iNewAspectRatio;
81+
82+
inline static DalmatiansFix* s_instance_ = nullptr;
83+
};
84+
85+
static std::unique_ptr<DalmatiansFix> g_fix;
22386

22487
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
22588
{
89+
UNREFERENCED_PARAMETER(lpReserved);
90+
22691
switch (ul_reason_for_call)
22792
{
22893
case DLL_PROCESS_ATTACH:
22994
{
230-
thisModule = hModule;
231-
HANDLE mainHandle = CreateThread(NULL, 0, Main, 0, NULL, 0);
232-
if (mainHandle)
233-
{
234-
SetThreadPriority(mainHandle, THREAD_PRIORITY_HIGHEST);
235-
CloseHandle(mainHandle);
236-
}
95+
DisableThreadLibraryCalls(hModule);
96+
97+
g_fix = std::make_unique<DalmatiansFix>(hModule);
98+
99+
g_fix->Start();
100+
101+
break;
102+
}
103+
104+
case DLL_PROCESS_DETACH:
105+
{
106+
g_fix->Shutdown();
107+
g_fix.reset();
237108
break;
238109
}
110+
239111
case DLL_THREAD_ATTACH:
240112
case DLL_THREAD_DETACH:
241-
case DLL_PROCESS_DETACH:
113+
default:
242114
break;
243115
}
116+
244117
return TRUE;
245-
}
118+
}

0 commit comments

Comments
 (0)