Clean up
This commit is contained in:
@@ -0,0 +1,186 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
std::wstring GetModuleFileNameW(HMODULE hModule)
|
||||
{
|
||||
static constexpr auto INITIAL_BUFFER_SIZE = MAX_PATH;
|
||||
static constexpr auto MAX_ITERATIONS = 7;
|
||||
std::wstring ret;
|
||||
auto bufferSize = INITIAL_BUFFER_SIZE;
|
||||
for (size_t iterations = 0; iterations < MAX_ITERATIONS; ++iterations)
|
||||
{
|
||||
ret.resize(bufferSize);
|
||||
auto charsReturned = GetModuleFileNameW(hModule, &ret[0], bufferSize);
|
||||
if (charsReturned < ret.length())
|
||||
{
|
||||
ret.resize(charsReturned);
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
bufferSize *= 2;
|
||||
}
|
||||
}
|
||||
return L"";
|
||||
}
|
||||
|
||||
auto starts_with = [](const std::wstring& big_str, const std::wstring& small_str) -> auto
|
||||
{
|
||||
return big_str.compare(0, small_str.length(), small_str) == 0;
|
||||
};
|
||||
|
||||
// Stores a list of loaded modules with their names, WITHOUT extension
|
||||
class ModuleList
|
||||
{
|
||||
public:
|
||||
enum class SearchLocation
|
||||
{
|
||||
All,
|
||||
LocalOnly,
|
||||
SystemOnly,
|
||||
};
|
||||
|
||||
// Initializes module list
|
||||
// Needs to be called before any calls to Get or GetAll
|
||||
void Enumerate(SearchLocation location = SearchLocation::All)
|
||||
{
|
||||
constexpr size_t INITIAL_SIZE = sizeof(HMODULE) * 256;
|
||||
HMODULE* modules = static_cast<HMODULE*>(malloc(INITIAL_SIZE));
|
||||
if (modules != nullptr)
|
||||
{
|
||||
typedef BOOL(WINAPI * Func)(HANDLE hProcess, HMODULE * lphModule, DWORD cb, LPDWORD lpcbNeeded);
|
||||
|
||||
HMODULE hLib = LoadLibrary(TEXT("kernel32"));
|
||||
assert(hLib != nullptr); // If this fails then everything is probably broken anyway
|
||||
|
||||
Func pEnumProcessModules = reinterpret_cast<Func>(GetProcAddress(hLib, "K32EnumProcessModules"));
|
||||
if (pEnumProcessModules == nullptr)
|
||||
{
|
||||
// Try psapi
|
||||
FreeLibrary(hLib);
|
||||
hLib = LoadLibrary(TEXT("psapi"));
|
||||
if (hLib != nullptr)
|
||||
{
|
||||
pEnumProcessModules = reinterpret_cast<Func>(GetProcAddress(hLib, "EnumProcessModules"));
|
||||
}
|
||||
}
|
||||
|
||||
if (pEnumProcessModules != nullptr)
|
||||
{
|
||||
const HANDLE currentProcess = GetCurrentProcess();
|
||||
DWORD cbNeeded = 0;
|
||||
if (pEnumProcessModules(currentProcess, modules, INITIAL_SIZE, &cbNeeded) != 0)
|
||||
{
|
||||
if (cbNeeded > INITIAL_SIZE)
|
||||
{
|
||||
HMODULE* newModules = static_cast<HMODULE*>(realloc(modules, cbNeeded));
|
||||
if (newModules != nullptr)
|
||||
{
|
||||
modules = newModules;
|
||||
|
||||
if (pEnumProcessModules(currentProcess, modules, cbNeeded, &cbNeeded) != 0)
|
||||
{
|
||||
EnumerateInternal(modules, location, cbNeeded / sizeof(HMODULE));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EnumerateInternal(modules, location, cbNeeded / sizeof(HMODULE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hLib != nullptr)
|
||||
{
|
||||
FreeLibrary(hLib);
|
||||
}
|
||||
|
||||
free(modules);
|
||||
}
|
||||
}
|
||||
|
||||
// Recreates module list
|
||||
void ReEnumerate(SearchLocation location = SearchLocation::All)
|
||||
{
|
||||
Clear();
|
||||
Enumerate(location);
|
||||
}
|
||||
|
||||
// Clears module list
|
||||
void Clear()
|
||||
{
|
||||
m_moduleList.clear();
|
||||
}
|
||||
|
||||
// Gets handle of a loaded module with given name, NULL otherwise
|
||||
HMODULE Get(const wchar_t* moduleName) const
|
||||
{
|
||||
// If vector is empty then we're trying to call it without calling Enumerate first
|
||||
assert(m_moduleList.size() != 0);
|
||||
|
||||
auto it = std::find_if(m_moduleList.begin(), m_moduleList.end(), [&](const auto& e) {
|
||||
return _wcsicmp(moduleName, std::get<1>(e).c_str()) == 0;
|
||||
});
|
||||
return it != m_moduleList.end() ? std::get<0>(*it) : nullptr;
|
||||
}
|
||||
|
||||
// Gets handles to all loaded modules with given name
|
||||
std::vector<HMODULE> GetAll(const wchar_t* moduleName) const
|
||||
{
|
||||
// If vector is empty then we're trying to call it without calling Enumerate first
|
||||
assert(m_moduleList.size() != 0);
|
||||
|
||||
std::vector<HMODULE> results;
|
||||
for (auto& e : m_moduleList)
|
||||
{
|
||||
if (_wcsicmp(moduleName, std::get<1>(e).c_str()) == 0)
|
||||
{
|
||||
results.push_back(std::get<0>(e));
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private:
|
||||
void EnumerateInternal(HMODULE* modules, SearchLocation location, size_t numModules)
|
||||
{
|
||||
const auto exeModulePath = GetModuleFileNameW(NULL).substr(0, GetModuleFileNameW(NULL).find_last_of(L"/\\"));
|
||||
|
||||
m_moduleList.reserve(numModules);
|
||||
for (size_t i = 0; i < numModules; i++)
|
||||
{
|
||||
// Obtain module name, with resizing if necessary
|
||||
auto moduleName = GetModuleFileNameW(*modules);
|
||||
|
||||
if (!moduleName.empty())
|
||||
{
|
||||
const wchar_t* nameBegin = wcsrchr(moduleName.c_str(), '\\') + 1;
|
||||
const wchar_t* dotPos = wcsrchr(nameBegin, '.');
|
||||
bool isLocal = starts_with(std::wstring(moduleName), exeModulePath);
|
||||
|
||||
if ((isLocal && location != SearchLocation::SystemOnly) || (!isLocal && location != SearchLocation::LocalOnly))
|
||||
{
|
||||
if (dotPos != nullptr)
|
||||
{
|
||||
m_moduleList.emplace_back(*modules, std::wstring(nameBegin, dotPos), isLocal);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_moduleList.emplace_back(*modules, nameBegin, isLocal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
modules++;
|
||||
}
|
||||
}
|
||||
|
||||
public: std::vector< std::tuple<HMODULE, std::wstring, bool> > m_moduleList;
|
||||
};
|
||||
@@ -0,0 +1,186 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<ProjectGuid>{CA479467-D518-46A2-AC86-3098ADA99FE5}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>PDLoader</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<TargetFrameworkVersion>
|
||||
</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<CLRSupport>false</CLRSupport>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<TargetName>dnsapi</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<TargetName>dnsapi</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>X64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>..\MemoryModule;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<ModuleDefinitionFile>x64.def</ModuleDefinitionFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_DEBUG;PDLOADER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<AdditionalIncludeDirectories>..\dependencies\MemoryModule;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<ModuleDefinitionFile>x64.def</ModuleDefinitionFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;PDLOADER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<ModuleDefinitionFile>x64.def</ModuleDefinitionFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NDEBUG;PDLOADER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<AdditionalIncludeDirectories>..\dependencies\MemoryModule;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<ModuleDefinitionFile>x64.def</ModuleDefinitionFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="exception.hpp" />
|
||||
<ClInclude Include="framework.h" />
|
||||
<ClInclude Include="ModuleList.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="x64.def" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="framework.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ModuleList.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="exception.hpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="x64.def">
|
||||
<Filter>Source Files</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,710 @@
|
||||
#include "framework.h"
|
||||
#include "exception.hpp"
|
||||
|
||||
HMODULE hm;
|
||||
std::vector<std::wstring> iniPaths;
|
||||
|
||||
bool iequals(std::wstring_view s1, std::wstring_view s2)
|
||||
{
|
||||
std::wstring str1(std::move(s1));
|
||||
std::wstring str2(std::move(s2));
|
||||
std::transform(str1.begin(), str1.end(), str1.begin(), [](wchar_t c) { return ::towlower(c); });
|
||||
std::transform(str2.begin(), str2.end(), str2.begin(), [](wchar_t c) { return ::towlower(c); });
|
||||
return (str1 == str2);
|
||||
}
|
||||
|
||||
std::wstring to_wstring(std::string_view cstr)
|
||||
{
|
||||
std::string str(std::move(cstr));
|
||||
auto charsReturned = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
|
||||
std::wstring wstrTo(charsReturned, 0);
|
||||
MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], charsReturned);
|
||||
return wstrTo;
|
||||
}
|
||||
|
||||
std::wstring SHGetKnownFolderPath(REFKNOWNFOLDERID rfid, DWORD dwFlags, HANDLE hToken)
|
||||
{
|
||||
std::wstring r;
|
||||
WCHAR* szSystemPath = nullptr;
|
||||
if (SUCCEEDED(SHGetKnownFolderPath(rfid, dwFlags, hToken, &szSystemPath)))
|
||||
{
|
||||
r = szSystemPath;
|
||||
}
|
||||
CoTaskMemFree(szSystemPath);
|
||||
return r;
|
||||
};
|
||||
|
||||
HMODULE LoadLibraryW(const std::wstring& lpLibFileName)
|
||||
{
|
||||
return LoadLibraryW(lpLibFileName.c_str());
|
||||
}
|
||||
|
||||
std::wstring GetCurrentDirectoryW()
|
||||
{
|
||||
static constexpr auto INITIAL_BUFFER_SIZE = MAX_PATH;
|
||||
static constexpr auto MAX_ITERATIONS = 7;
|
||||
std::wstring ret;
|
||||
auto bufferSize = INITIAL_BUFFER_SIZE;
|
||||
for (size_t iterations = 0; iterations < MAX_ITERATIONS; ++iterations)
|
||||
{
|
||||
ret.resize(bufferSize);
|
||||
auto charsReturned = GetCurrentDirectoryW(bufferSize, &ret[0]);
|
||||
if (charsReturned < ret.length())
|
||||
{
|
||||
ret.resize(charsReturned);
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
bufferSize *= 2;
|
||||
}
|
||||
}
|
||||
return L"";
|
||||
}
|
||||
|
||||
UINT GetPrivateProfileIntW(LPCWSTR lpAppName, LPCWSTR lpKeyName, INT nDefault, const std::vector<std::wstring>& fileNames)
|
||||
{
|
||||
for (const auto& file : fileNames)
|
||||
{
|
||||
nDefault = GetPrivateProfileIntW(lpAppName, lpKeyName, nDefault, file.c_str());
|
||||
}
|
||||
return nDefault;
|
||||
}
|
||||
|
||||
std::wstring GetSelfName()
|
||||
{
|
||||
const std::wstring moduleFileName = GetModuleFileNameW(hm);
|
||||
return moduleFileName.substr(moduleFileName.find_last_of(L"/\\") + 1);
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
void GetSections(T&& h, Args... args)
|
||||
{
|
||||
const std::set< std::string_view, std::less<> > s = { args... };
|
||||
size_t dwLoadOffset = (size_t)GetModuleHandle(NULL);
|
||||
BYTE* pImageBase = reinterpret_cast<BYTE*>(dwLoadOffset);
|
||||
PIMAGE_DOS_HEADER pDosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(dwLoadOffset);
|
||||
PIMAGE_NT_HEADERS pNtHeader = reinterpret_cast<PIMAGE_NT_HEADERS>(pImageBase + pDosHeader->e_lfanew);
|
||||
PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNtHeader);
|
||||
for (int iSection = 0; iSection < pNtHeader->FileHeader.NumberOfSections; ++iSection, ++pSection)
|
||||
{
|
||||
auto pszSectionName = reinterpret_cast<const char*>(pSection->Name);
|
||||
if (s.find(pszSectionName) != s.end())
|
||||
{
|
||||
DWORD dwPhysSize = (pSection->Misc.VirtualSize + 4095) & ~4095;
|
||||
std::forward<T>(h)(pSection, dwLoadOffset, dwPhysSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Kernel32ExportsNames
|
||||
{
|
||||
eGetStartupInfoA,
|
||||
eGetStartupInfoW,
|
||||
eGetModuleHandleA,
|
||||
eGetModuleHandleW,
|
||||
eGetProcAddress,
|
||||
eGetShortPathNameA,
|
||||
eFindNextFileA,
|
||||
eFindNextFileW,
|
||||
eLoadLibraryA,
|
||||
eLoadLibraryW,
|
||||
eFreeLibrary,
|
||||
eCreateEventA,
|
||||
eCreateEventW,
|
||||
eGetSystemInfo,
|
||||
eInterlockedCompareExchange,
|
||||
eSleep,
|
||||
|
||||
Kernel32ExportsNamesCount
|
||||
};
|
||||
|
||||
enum Kernel32ExportsData
|
||||
{
|
||||
IATPtr,
|
||||
ProcAddress,
|
||||
|
||||
Kernel32ExportsDataCount
|
||||
};
|
||||
|
||||
size_t Kernel32Data[Kernel32ExportsNamesCount][Kernel32ExportsDataCount];
|
||||
|
||||
static LONG OriginalLibraryLoaded = 0;
|
||||
void LoadOriginalLibrary()
|
||||
{
|
||||
if (_InterlockedCompareExchange(&OriginalLibraryLoaded, 1, 0) != 0) return;
|
||||
|
||||
auto szSelfName = GetSelfName();
|
||||
auto szSystemPath = SHGetKnownFolderPath(FOLDERID_System, 0, nullptr) + L'\\' + szSelfName;
|
||||
auto szLocalPath = GetModuleFileNameW(hm); szLocalPath = szLocalPath.substr(0, szLocalPath.find_last_of(L"/\\") + 1);
|
||||
|
||||
if (iequals(szSelfName, L"dnsapi.dll")) {
|
||||
dnsapi.LoadOriginalLibrary(LoadLibraryW(szSystemPath));
|
||||
}
|
||||
}
|
||||
|
||||
void FindFiles(WIN32_FIND_DATAW* fd)
|
||||
{
|
||||
auto dir = GetCurrentDirectoryW();
|
||||
|
||||
HANDLE dvaFile = FindFirstFileW(L"*.dva", fd);
|
||||
if (dvaFile != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
do {
|
||||
if (!(fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
||||
{
|
||||
auto pos = wcslen(fd->cFileName);
|
||||
|
||||
if (fd->cFileName[pos - 4] == '.' &&
|
||||
(fd->cFileName[pos - 3] == 'd' || fd->cFileName[pos - 3] == 'D') &&
|
||||
(fd->cFileName[pos - 2] == 'v' || fd->cFileName[pos - 2] == 'V') &&
|
||||
(fd->cFileName[pos - 1] == 'a' || fd->cFileName[pos - 1] == 'A'))
|
||||
{
|
||||
auto path = dir + L'\\' + fd->cFileName;
|
||||
|
||||
if (GetModuleHandle(path.c_str()) == NULL)
|
||||
{
|
||||
auto h = LoadLibraryW(path);
|
||||
SetCurrentDirectoryW(dir.c_str()); //in case dva switched it
|
||||
|
||||
if (h == NULL)
|
||||
{
|
||||
auto e = GetLastError();
|
||||
if (e != ERROR_DLL_INIT_FAILED) // in case dllmain returns false
|
||||
{
|
||||
std::wstring msg = L"Unable to load " + std::wstring(fd->cFileName) + L". Error: " + std::to_wstring(e);
|
||||
MessageBoxW(0, msg.c_str(), L"PD Loader", MB_ICONERROR);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto procedure = (void(*)())GetProcAddress(h, "InitializeDVA");
|
||||
|
||||
if (procedure != NULL)
|
||||
{
|
||||
procedure();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (FindNextFileW(dvaFile, fd));
|
||||
FindClose(dvaFile);
|
||||
}
|
||||
}
|
||||
|
||||
void LoadPlugins()
|
||||
{
|
||||
auto oldDir = GetCurrentDirectoryW(); // store the current directory
|
||||
|
||||
auto szSelfPath = GetModuleFileNameW(hm).substr(0, GetModuleFileNameW(hm).find_last_of(L"/\\") + 1);
|
||||
SetCurrentDirectoryW(szSelfPath.c_str());
|
||||
|
||||
auto nWantsToLoadPlugins = GetPrivateProfileIntW(L"global", L"enable", TRUE, iniPaths);
|
||||
|
||||
if (nWantsToLoadPlugins)
|
||||
{
|
||||
WIN32_FIND_DATAW fd;
|
||||
|
||||
SetCurrentDirectoryW(szSelfPath.c_str());
|
||||
|
||||
if (SetCurrentDirectoryW(L"plugins\\"))
|
||||
FindFiles(&fd);
|
||||
}
|
||||
|
||||
SetCurrentDirectoryW(oldDir.c_str()); // Reset the current directory
|
||||
}
|
||||
|
||||
static LONG LoadedPluginsYet = 0;
|
||||
void LoadEverything()
|
||||
{
|
||||
if (_InterlockedCompareExchange(&LoadedPluginsYet, 1, 0) != 0) return;
|
||||
|
||||
LoadOriginalLibrary();
|
||||
LoadPlugins();
|
||||
}
|
||||
|
||||
static LONG RestoredOnce = 0;
|
||||
void LoadPluginsAndRestoreIAT(uintptr_t retaddr)
|
||||
{
|
||||
bool calledFromBind = false;
|
||||
|
||||
//steam drm check
|
||||
GetSections([&](PIMAGE_SECTION_HEADER pSection, size_t dwLoadOffset, DWORD dwPhysSize) {
|
||||
auto dwStart = static_cast<uintptr_t>(dwLoadOffset + pSection->VirtualAddress);
|
||||
auto dwEnd = dwStart + dwPhysSize;
|
||||
if (retaddr >= dwStart && retaddr <= dwEnd)
|
||||
calledFromBind = true;
|
||||
}, ".bind");
|
||||
|
||||
if (calledFromBind) return;
|
||||
|
||||
if (_InterlockedCompareExchange(&RestoredOnce, 1, 0) != 0) return;
|
||||
|
||||
LoadEverything();
|
||||
|
||||
for (size_t i = 0; i < Kernel32ExportsNamesCount; i++)
|
||||
{
|
||||
if (Kernel32Data[i][IATPtr] && Kernel32Data[i][ProcAddress])
|
||||
{
|
||||
auto ptr = (size_t*)Kernel32Data[i][IATPtr];
|
||||
DWORD dwProtect[2];
|
||||
VirtualProtect(ptr, sizeof(size_t), PAGE_EXECUTE_READWRITE, &dwProtect[0]);
|
||||
*ptr = Kernel32Data[i][ProcAddress];
|
||||
VirtualProtect(ptr, sizeof(size_t), dwProtect[0], &dwProtect[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WINAPI CustomGetStartupInfoA(LPSTARTUPINFOA lpStartupInfo)
|
||||
{
|
||||
LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress());
|
||||
return GetStartupInfoA(lpStartupInfo);
|
||||
}
|
||||
|
||||
void WINAPI CustomGetStartupInfoW(LPSTARTUPINFOW lpStartupInfo)
|
||||
{
|
||||
LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress());
|
||||
return GetStartupInfoW(lpStartupInfo);
|
||||
}
|
||||
|
||||
HMODULE WINAPI CustomGetModuleHandleA(LPCSTR lpModuleName)
|
||||
{
|
||||
LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress());
|
||||
return GetModuleHandleA(lpModuleName);
|
||||
}
|
||||
|
||||
HMODULE WINAPI CustomGetModuleHandleW(LPCWSTR lpModuleName)
|
||||
{
|
||||
LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress());
|
||||
return GetModuleHandleW(lpModuleName);
|
||||
}
|
||||
|
||||
FARPROC WINAPI CustomGetProcAddress(HMODULE hModule, LPCSTR lpProcName)
|
||||
{
|
||||
LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress());
|
||||
return GetProcAddress(hModule, lpProcName);
|
||||
}
|
||||
|
||||
DWORD WINAPI CustomGetShortPathNameA(LPCSTR lpszLongPath, LPSTR lpszShortPath, DWORD cchBuffer)
|
||||
{
|
||||
LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress());
|
||||
return GetShortPathNameA(lpszLongPath, lpszShortPath, cchBuffer);
|
||||
}
|
||||
|
||||
BOOL WINAPI CustomFindNextFileA(HANDLE hFindFile, LPWIN32_FIND_DATAA lpFindFileData)
|
||||
{
|
||||
LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress());
|
||||
return FindNextFileA(hFindFile, lpFindFileData);
|
||||
}
|
||||
|
||||
BOOL WINAPI CustomFindNextFileW(HANDLE hFindFile, LPWIN32_FIND_DATAW lpFindFileData)
|
||||
{
|
||||
LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress());
|
||||
return FindNextFileW(hFindFile, lpFindFileData);
|
||||
}
|
||||
|
||||
HMODULE WINAPI CustomLoadLibraryA(LPCSTR lpLibFileName)
|
||||
{
|
||||
LoadOriginalLibrary();
|
||||
|
||||
return LoadLibraryA(lpLibFileName);
|
||||
}
|
||||
|
||||
HMODULE WINAPI CustomLoadLibraryW(LPCWSTR lpLibFileName)
|
||||
{
|
||||
LoadOriginalLibrary();
|
||||
|
||||
return LoadLibraryW(lpLibFileName);
|
||||
}
|
||||
|
||||
BOOL WINAPI CustomFreeLibrary(HMODULE hLibModule)
|
||||
{
|
||||
if (hLibModule != hm)
|
||||
return FreeLibrary(hLibModule);
|
||||
else
|
||||
return !NULL;
|
||||
}
|
||||
|
||||
HANDLE WINAPI CustomCreateEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCSTR lpName)
|
||||
{
|
||||
LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress());
|
||||
return CreateEventA(lpEventAttributes, bManualReset, bInitialState, lpName);
|
||||
}
|
||||
|
||||
HANDLE WINAPI CustomCreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCWSTR lpName)
|
||||
{
|
||||
LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress());
|
||||
return CreateEventW(lpEventAttributes, bManualReset, bInitialState, lpName);
|
||||
}
|
||||
|
||||
void WINAPI CustomGetSystemInfo(LPSYSTEM_INFO lpSystemInfo)
|
||||
{
|
||||
LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress());
|
||||
return GetSystemInfo(lpSystemInfo);
|
||||
}
|
||||
|
||||
LONG WINAPI CustomInterlockedCompareExchange(LONG volatile* Destination, LONG ExChange, LONG Comperand)
|
||||
{
|
||||
LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress());
|
||||
return _InterlockedCompareExchange(Destination, ExChange, Comperand);
|
||||
}
|
||||
|
||||
void WINAPI CustomSleep(DWORD dwMilliseconds)
|
||||
{
|
||||
LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress());
|
||||
return Sleep(dwMilliseconds);
|
||||
}
|
||||
|
||||
bool HookKernel32IAT(HMODULE mod, bool exe)
|
||||
{
|
||||
auto hExecutableInstance = (size_t)mod;
|
||||
IMAGE_NT_HEADERS* ntHeader = (IMAGE_NT_HEADERS*)(hExecutableInstance + ((IMAGE_DOS_HEADER*)hExecutableInstance)->e_lfanew);
|
||||
IMAGE_IMPORT_DESCRIPTOR* pImports = (IMAGE_IMPORT_DESCRIPTOR*)(hExecutableInstance + ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
|
||||
size_t nNumImports = ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size / sizeof(IMAGE_IMPORT_DESCRIPTOR) - 1;
|
||||
|
||||
if (exe)
|
||||
{
|
||||
Kernel32Data[eGetStartupInfoA][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetStartupInfoA");
|
||||
Kernel32Data[eGetStartupInfoW][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetStartupInfoW");
|
||||
Kernel32Data[eGetModuleHandleA][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetModuleHandleA");
|
||||
Kernel32Data[eGetModuleHandleW][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetModuleHandleW");
|
||||
Kernel32Data[eGetProcAddress][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetProcAddress");
|
||||
Kernel32Data[eGetShortPathNameA][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetShortPathNameA");
|
||||
Kernel32Data[eFindNextFileA][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "FindNextFileA");
|
||||
Kernel32Data[eFindNextFileW][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "FindNextFileW");
|
||||
Kernel32Data[eLoadLibraryA][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "LoadLibraryA");
|
||||
Kernel32Data[eLoadLibraryW][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "LoadLibraryW");
|
||||
Kernel32Data[eFreeLibrary][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "FreeLibrary");
|
||||
Kernel32Data[eCreateEventA][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "CreateEventA");
|
||||
Kernel32Data[eCreateEventW][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "CreateEventW");
|
||||
Kernel32Data[eGetSystemInfo][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetSystemInfo");
|
||||
Kernel32Data[eInterlockedCompareExchange][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "InterlockedCompareExchange");
|
||||
Kernel32Data[eSleep][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "Sleep");
|
||||
}
|
||||
|
||||
uint32_t matchedImports = 0;
|
||||
|
||||
auto PatchIAT = [&](size_t start, size_t end, size_t exe_end)
|
||||
{
|
||||
for (size_t i = 0; i < nNumImports; i++)
|
||||
{
|
||||
if (hExecutableInstance + (pImports + i)->FirstThunk > start && !(end && hExecutableInstance + (pImports + i)->FirstThunk > end))
|
||||
end = hExecutableInstance + (pImports + i)->FirstThunk;
|
||||
}
|
||||
|
||||
if (!end) { end = start + 0x100; }
|
||||
if (end > exe_end) //for very broken exes
|
||||
{
|
||||
start = hExecutableInstance;
|
||||
end = exe_end;
|
||||
}
|
||||
|
||||
for (auto i = start; i < end; i += sizeof(size_t))
|
||||
{
|
||||
DWORD dwProtect[2];
|
||||
VirtualProtect((size_t*)i, sizeof(size_t), PAGE_EXECUTE_READWRITE, &dwProtect[0]);
|
||||
|
||||
auto ptr = *(size_t*)i;
|
||||
if (!ptr)
|
||||
continue;
|
||||
|
||||
if (ptr == Kernel32Data[eGetStartupInfoA][ProcAddress])
|
||||
{
|
||||
if (exe) Kernel32Data[eGetStartupInfoA][IATPtr] = i;
|
||||
*(size_t*)i = (size_t)CustomGetStartupInfoA;
|
||||
matchedImports++;
|
||||
}
|
||||
else if (ptr == Kernel32Data[eGetStartupInfoW][ProcAddress])
|
||||
{
|
||||
if (exe) Kernel32Data[eGetStartupInfoW][IATPtr] = i;
|
||||
*(size_t*)i = (size_t)CustomGetStartupInfoW;
|
||||
matchedImports++;
|
||||
}
|
||||
else if (ptr == Kernel32Data[eGetModuleHandleA][ProcAddress])
|
||||
{
|
||||
if (exe) Kernel32Data[eGetModuleHandleA][IATPtr] = i;
|
||||
*(size_t*)i = (size_t)CustomGetModuleHandleA;
|
||||
matchedImports++;
|
||||
}
|
||||
else if (ptr == Kernel32Data[eGetModuleHandleW][ProcAddress])
|
||||
{
|
||||
if (exe) Kernel32Data[eGetModuleHandleW][IATPtr] = i;
|
||||
*(size_t*)i = (size_t)CustomGetModuleHandleW;
|
||||
matchedImports++;
|
||||
}
|
||||
else if (ptr == Kernel32Data[eGetProcAddress][ProcAddress])
|
||||
{
|
||||
if (exe) Kernel32Data[eGetProcAddress][IATPtr] = i;
|
||||
*(size_t*)i = (size_t)CustomGetProcAddress;
|
||||
matchedImports++;
|
||||
}
|
||||
else if (ptr == Kernel32Data[eGetShortPathNameA][ProcAddress])
|
||||
{
|
||||
if (exe) Kernel32Data[eGetShortPathNameA][IATPtr] = i;
|
||||
*(size_t*)i = (size_t)CustomGetShortPathNameA;
|
||||
matchedImports++;
|
||||
}
|
||||
else if (ptr == Kernel32Data[eFindNextFileA][ProcAddress])
|
||||
{
|
||||
if (exe) Kernel32Data[eFindNextFileA][IATPtr] = i;
|
||||
*(size_t*)i = (size_t)CustomFindNextFileA;
|
||||
matchedImports++;
|
||||
}
|
||||
else if (ptr == Kernel32Data[eFindNextFileW][ProcAddress])
|
||||
{
|
||||
if (exe) Kernel32Data[eFindNextFileW][IATPtr] = i;
|
||||
*(size_t*)i = (size_t)CustomFindNextFileW;
|
||||
matchedImports++;
|
||||
}
|
||||
else if (ptr == Kernel32Data[eLoadLibraryA][ProcAddress])
|
||||
{
|
||||
if (exe) Kernel32Data[eLoadLibraryA][IATPtr] = i;
|
||||
*(size_t*)i = (size_t)CustomLoadLibraryA;
|
||||
matchedImports++;
|
||||
}
|
||||
else if (ptr == Kernel32Data[eLoadLibraryW][ProcAddress])
|
||||
{
|
||||
if (exe) Kernel32Data[eLoadLibraryW][IATPtr] = i;
|
||||
*(size_t*)i = (size_t)CustomLoadLibraryW;
|
||||
matchedImports++;
|
||||
}
|
||||
else if (ptr == Kernel32Data[eFreeLibrary][ProcAddress])
|
||||
{
|
||||
if (exe) Kernel32Data[eFreeLibrary][IATPtr] = i;
|
||||
*(size_t*)i = (size_t)CustomFreeLibrary;
|
||||
matchedImports++;
|
||||
}
|
||||
else if (ptr == Kernel32Data[eCreateEventA][ProcAddress])
|
||||
{
|
||||
if (exe) Kernel32Data[eCreateEventA][IATPtr] = i;
|
||||
*(size_t*)i = (size_t)CustomCreateEventA;
|
||||
matchedImports++;
|
||||
}
|
||||
else if (ptr == Kernel32Data[eCreateEventW][ProcAddress])
|
||||
{
|
||||
if (exe) Kernel32Data[eCreateEventW][IATPtr] = i;
|
||||
*(size_t*)i = (size_t)CustomCreateEventW;
|
||||
matchedImports++;
|
||||
}
|
||||
else if (ptr == Kernel32Data[eGetSystemInfo][ProcAddress])
|
||||
{
|
||||
if (exe) Kernel32Data[eGetSystemInfo][IATPtr] = i;
|
||||
*(size_t*)i = (size_t)CustomGetSystemInfo;
|
||||
matchedImports++;
|
||||
}
|
||||
else if (ptr == Kernel32Data[eInterlockedCompareExchange][ProcAddress])
|
||||
{
|
||||
if (exe) Kernel32Data[eInterlockedCompareExchange][IATPtr] = i;
|
||||
*(size_t*)i = (size_t)CustomInterlockedCompareExchange;
|
||||
matchedImports++;
|
||||
}
|
||||
else if (ptr == Kernel32Data[eSleep][ProcAddress])
|
||||
{
|
||||
if (exe) Kernel32Data[eSleep][IATPtr] = i;
|
||||
*(size_t*)i = (size_t)CustomSleep;
|
||||
matchedImports++;
|
||||
}
|
||||
|
||||
VirtualProtect((size_t*)i, sizeof(size_t), dwProtect[0], &dwProtect[1]);
|
||||
}
|
||||
};
|
||||
|
||||
static auto getSection = [](const PIMAGE_NT_HEADERS nt_headers, unsigned section) -> PIMAGE_SECTION_HEADER
|
||||
{
|
||||
return reinterpret_cast<PIMAGE_SECTION_HEADER>(
|
||||
(UCHAR*)nt_headers->OptionalHeader.DataDirectory +
|
||||
nt_headers->OptionalHeader.NumberOfRvaAndSizes * sizeof(IMAGE_DATA_DIRECTORY) +
|
||||
section * sizeof(IMAGE_SECTION_HEADER));
|
||||
};
|
||||
|
||||
static auto getSectionEnd = [](IMAGE_NT_HEADERS* ntHeader, size_t inst) -> auto
|
||||
{
|
||||
auto sec = getSection(ntHeader, ntHeader->FileHeader.NumberOfSections - 1);
|
||||
auto secSize = max(sec->SizeOfRawData, sec->Misc.VirtualSize);
|
||||
auto end = inst + max(sec->PointerToRawData, sec->VirtualAddress) + secSize;
|
||||
return end;
|
||||
};
|
||||
|
||||
auto hExecutableInstance_end = getSectionEnd(ntHeader, hExecutableInstance);
|
||||
|
||||
// Find kernel32.dll
|
||||
for (size_t i = 0; i < nNumImports; i++)
|
||||
{
|
||||
if ((size_t)(hExecutableInstance + (pImports + i)->Name) < hExecutableInstance_end)
|
||||
{
|
||||
if (!_stricmp((const char*)(hExecutableInstance + (pImports + i)->Name), "KERNEL32.DLL"))
|
||||
PatchIAT(hExecutableInstance + (pImports + i)->FirstThunk, 0, hExecutableInstance_end);
|
||||
}
|
||||
}
|
||||
|
||||
// Fixing ordinals
|
||||
auto szSelfName = GetSelfName();
|
||||
|
||||
static auto PatchOrdinals = [&szSelfName](size_t hInstance)
|
||||
{
|
||||
IMAGE_NT_HEADERS* ntHeader = (IMAGE_NT_HEADERS*)(hInstance + ((IMAGE_DOS_HEADER*)hInstance)->e_lfanew);
|
||||
IMAGE_IMPORT_DESCRIPTOR* pImports = (IMAGE_IMPORT_DESCRIPTOR*)(hInstance + ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
|
||||
size_t nNumImports = ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size / sizeof(IMAGE_IMPORT_DESCRIPTOR) - 1;
|
||||
|
||||
for (size_t i = 0; i < nNumImports; i++)
|
||||
{
|
||||
if ((size_t)(hInstance + (pImports + i)->Name) < getSectionEnd(ntHeader, (size_t)hInstance))
|
||||
{
|
||||
if (iequals(szSelfName, (to_wstring((const char*)(hInstance + (pImports + i)->Name)))))
|
||||
{
|
||||
PIMAGE_THUNK_DATA thunk = (PIMAGE_THUNK_DATA)(hInstance + (pImports + i)->OriginalFirstThunk);
|
||||
size_t j = 0;
|
||||
while (thunk->u1.Function)
|
||||
{
|
||||
if (thunk->u1.Ordinal & IMAGE_ORDINAL_FLAG)
|
||||
{
|
||||
PIMAGE_IMPORT_BY_NAME import = (PIMAGE_IMPORT_BY_NAME)(hInstance + thunk->u1.AddressOfData);
|
||||
void** p = (void**)(hInstance + (pImports + i)->FirstThunk);
|
||||
}
|
||||
++thunk;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ModuleList dlls;
|
||||
dlls.Enumerate(ModuleList::SearchLocation::LocalOnly);
|
||||
for (auto& e : dlls.m_moduleList)
|
||||
{
|
||||
PatchOrdinals((size_t)std::get<HMODULE>(e));
|
||||
}
|
||||
return matchedImports > 0;
|
||||
}
|
||||
|
||||
LONG WINAPI CustomUnhandledExceptionFilter(LPEXCEPTION_POINTERS ExceptionInfo)
|
||||
{
|
||||
// step 1: write minidump
|
||||
wchar_t modulename[MAX_PATH];
|
||||
wchar_t filename[MAX_PATH];
|
||||
wchar_t timestamp[128];
|
||||
__time64_t time;
|
||||
struct tm ltime;
|
||||
HANDLE hFile;
|
||||
HWND hWnd;
|
||||
|
||||
wchar_t* modulenameptr = NULL;
|
||||
if (GetModuleFileNameW(GetModuleHandle(NULL), modulename, _countof(modulename)) != 0)
|
||||
{
|
||||
modulenameptr = wcsrchr(modulename, '\\');
|
||||
*modulenameptr = L'\0';
|
||||
modulenameptr += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
*modulenameptr = L'err.err';
|
||||
}
|
||||
|
||||
_time64(&time);
|
||||
_localtime64_s(<ime, &time);
|
||||
wcsftime(timestamp, _countof(timestamp), L"%Y%m%d%H%M%S", <ime);
|
||||
swprintf_s(filename, L"%s\\%s\\%s.%s.dmp", modulename, L"logs", modulenameptr, timestamp);
|
||||
|
||||
hFile = CreateFileW(filename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if (hFile != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
MINIDUMP_EXCEPTION_INFORMATION ex;
|
||||
memset(&ex, 0, sizeof(ex));
|
||||
ex.ThreadId = GetCurrentThreadId();
|
||||
ex.ExceptionPointers = ExceptionInfo;
|
||||
ex.ClientPointers = TRUE;
|
||||
|
||||
if (FAILED(MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpWithDataSegs, &ex, NULL, NULL)))
|
||||
{
|
||||
}
|
||||
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
|
||||
// step 2: write log
|
||||
// Logs exception into buffer and writes to file
|
||||
swprintf_s(filename, L"%s\\%s\\%s.%s.log", modulename, L"logs", modulenameptr, timestamp);
|
||||
hFile = CreateFileW(filename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if (hFile != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
auto Log = [ExceptionInfo, hFile](char* buffer, size_t size, bool reg, bool stack, bool trace)
|
||||
{
|
||||
if (LogException(buffer, size, (LPEXCEPTION_POINTERS)ExceptionInfo, reg, stack, trace))
|
||||
{
|
||||
DWORD NumberOfBytesWritten = 0;
|
||||
WriteFile(hFile, buffer, strlen(buffer), &NumberOfBytesWritten, NULL);
|
||||
}
|
||||
};
|
||||
|
||||
// Try to make a very descriptive exception, for that we need to malloc a huge buffer...
|
||||
if (auto buffer = (char*)malloc(max_logsize_ever))
|
||||
{
|
||||
Log(buffer, max_logsize_ever, true, true, true);
|
||||
free(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use a static buffer, no need for any allocation
|
||||
static const auto size = max_logsize_basic + max_logsize_regs + max_logsize_stackdump;
|
||||
static char static_buf[size];
|
||||
static_assert(size <= max_static_buffer, "Static buffer is too big");
|
||||
|
||||
Log(buffer = static_buf, sizeof(static_buf), true, true, false);
|
||||
}
|
||||
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
|
||||
// step 3: exit the application
|
||||
ShowCursor(TRUE);
|
||||
hWnd = FindWindowW(0, L"");
|
||||
SetForegroundWindow(hWnd);
|
||||
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
std::wstring modulePath = GetModuleFileNameW(hm);
|
||||
std::wstring moduleName = modulePath.substr(modulePath.find_last_of(L"/\\") + 1);
|
||||
moduleName.resize(moduleName.find_last_of(L'.'));
|
||||
modulePath.resize(modulePath.find_last_of(L"/\\") + 1);
|
||||
iniPaths.emplace_back(modulePath + moduleName + L".ini");
|
||||
iniPaths.emplace_back(modulePath + L"plugins\\config.ini");
|
||||
|
||||
std::wstring m = GetModuleFileNameW(NULL);
|
||||
m = m.substr(0, m.find_last_of(L"/\\") + 1) + L"logs";
|
||||
|
||||
auto FolderExists = [](LPCWSTR szPath) -> BOOL
|
||||
{
|
||||
DWORD dwAttrib = GetFileAttributes(szPath);
|
||||
return (dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
|
||||
};
|
||||
|
||||
if (FolderExists(m.c_str()))
|
||||
{
|
||||
SetUnhandledExceptionFilter(CustomUnhandledExceptionFilter);
|
||||
// Now stub out CustomUnhandledExceptionFilter so NO ONE ELSE can set it!
|
||||
uint32_t ret = 0x909090C3; //ret
|
||||
DWORD protect[2];
|
||||
VirtualProtect(&SetUnhandledExceptionFilter, sizeof(ret), PAGE_EXECUTE_READWRITE, &protect[0]);
|
||||
memcpy(&SetUnhandledExceptionFilter, &ret, sizeof(ret));
|
||||
VirtualProtect(&SetUnhandledExceptionFilter, sizeof(ret), protect[0], &protect[1]);
|
||||
}
|
||||
|
||||
LoadEverything();
|
||||
|
||||
}
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID /*lpReserved*/)
|
||||
{
|
||||
if (reason == DLL_PROCESS_ATTACH)
|
||||
{
|
||||
hm = hModule;
|
||||
Init();
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
@@ -0,0 +1,678 @@
|
||||
#pragma once
|
||||
/*
|
||||
* Unhandled Exception Tracer
|
||||
* by LINK/2012 <dma_2012@hotmail.com>
|
||||
*
|
||||
* This source code is offered for use in the public domain. You may
|
||||
* use, modify or distribute it freely.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful but
|
||||
* WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
|
||||
* DISCLAIMED. This includes but is not limited to warranties of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#include <cassert>
|
||||
#include <DbgHelp.h>
|
||||
#pragma comment(lib, "Dbghelp.lib")
|
||||
|
||||
/*
|
||||
* Special Note:
|
||||
* Try not to allocate any memory in this file!
|
||||
* Allocation after a exception may not be a good idea...
|
||||
*/
|
||||
|
||||
#define LODWORD(_qw) ((DWORD)(_qw))
|
||||
#define HIDWORD(_qw) ((DWORD)(((_qw) >> 32) & 0xffffffff))
|
||||
|
||||
// General constants
|
||||
static const int sizeof_word = sizeof(void*); // Size of a CPU word (4 bytes on x86)
|
||||
static const int max_chars_per_print = MAX_PATH + 256; // Max characters per Print() call
|
||||
static const int symbol_max = 256; // Max size of a symbol (func symbol, var symbol, etc)
|
||||
static const int max_static_buffer = 4096; // Max static buffer for logging
|
||||
|
||||
// Stackdump constants
|
||||
static const int stackdump_max_words = 60; // max number of CPU words that the stackdump should dump
|
||||
static const int stackdump_words_per_line = 6; // max CPU words in a single line
|
||||
static const int stackdump_line_count = (stackdump_max_words / stackdump_words_per_line) + 1;
|
||||
|
||||
// Backtrace constants
|
||||
static const int max_backtrace_ever = 100;
|
||||
static const int max_backtrace = 20;
|
||||
|
||||
// Maximum log size constants
|
||||
static const int max_logsize_basic = (MAX_PATH + 200); // module path + other text
|
||||
static const int max_logsize_regs = 32 + (4 * 4 * 28); // info + (regsPerLine * numLines * charsPerReg)
|
||||
static const int max_logsize_stackdump = 32 + 80 + (stackdump_line_count * 32) + (10 * stackdump_words_per_line * stackdump_line_count);
|
||||
static const int max_logsize_backtrace = 32 + max_backtrace_ever * (MAX_PATH + symbol_max + 90);
|
||||
static const int max_logsize_ever = 32 + max_logsize_basic + max_logsize_regs + max_logsize_stackdump + max_logsize_backtrace;
|
||||
|
||||
// Internal
|
||||
class ExceptionTracer;
|
||||
class StackTrace;
|
||||
static HMODULE GetModuleFromAddress(LPVOID address);
|
||||
static const char* GetExceptionCodeString(unsigned int code);
|
||||
static const char* FindModuleName(HMODULE module, char* output, DWORD size);
|
||||
static int LogException(char* buffer, size_t max, LPEXCEPTION_POINTERS pException, bool bLogRegisters, bool bLogStack, bool bLogBacktrace);
|
||||
static LPTOP_LEVEL_EXCEPTION_FILTER PrevFilter = nullptr;
|
||||
static void(*ExceptionCallback)(const char* buffer) = nullptr;
|
||||
|
||||
// Exportable
|
||||
int InstallExceptionCatcher(void(*OnException)(const char* log));
|
||||
|
||||
/*
|
||||
* ExceptionTrace
|
||||
* This class is responssible for tracing all possible informations about an LPEXCEPTION_POINTER
|
||||
*/
|
||||
class ExceptionTracer
|
||||
{
|
||||
public:
|
||||
ExceptionTracer(char* buffer, size_t max, LPEXCEPTION_POINTERS pException);
|
||||
void PrintUnhandledException();
|
||||
void PrintRegisters();
|
||||
void PrintStackdump();
|
||||
void PrintBacktrace();
|
||||
|
||||
void EnterScope();
|
||||
void LeaveScope();
|
||||
void Print(const char* fmt, ...);
|
||||
void NewLine() { Print("\n%s", spc); }
|
||||
|
||||
protected:
|
||||
EXCEPTION_POINTERS& exception;
|
||||
EXCEPTION_RECORD& record;
|
||||
CONTEXT& context;
|
||||
HMODULE module;
|
||||
|
||||
char* buffer; // Logging buffer
|
||||
size_t len; // Logged length
|
||||
size_t max; // Maximum we can log in that buffer
|
||||
|
||||
char spc[(10 * 4) + 1]; // Scope/spacing buffer, 4 spaces per scope, max 10 scopes
|
||||
size_t nspc; // Number spaces used up there
|
||||
};
|
||||
|
||||
/*
|
||||
* StackTracer
|
||||
* Responssible for backtracing an stack from a context
|
||||
*/
|
||||
class StackTracer
|
||||
{
|
||||
public:
|
||||
struct Trace
|
||||
{
|
||||
// The following values may be null (any)
|
||||
HMODULE module; // The module the func related to this frame is located
|
||||
void* pc; // Program counter at func related to this frame (EIP)
|
||||
void* ret; // Return address for the frame
|
||||
void* frame; // The frame address (EBP)
|
||||
void* stack; // The stack pointer at the frame (ESP)
|
||||
};
|
||||
|
||||
StackTracer(const CONTEXT& context);
|
||||
Trace* Walk();
|
||||
|
||||
private:
|
||||
Trace trace;
|
||||
DWORD old_options;
|
||||
CONTEXT context;
|
||||
STACKFRAME64 frame;
|
||||
};
|
||||
|
||||
/*
|
||||
* TheUnhandledExceptionFilter
|
||||
* Logs an unhandled exception
|
||||
*/
|
||||
static LONG CALLBACK TheUnhandledExceptionFilter(LPEXCEPTION_POINTERS pException)
|
||||
{
|
||||
// Logs exception into buffer and calls the callback
|
||||
auto Log = [pException](char* buffer, size_t size, bool reg, bool stack, bool trace)
|
||||
{
|
||||
if (LogException(buffer, size, (LPEXCEPTION_POINTERS)pException, reg, stack, trace))
|
||||
ExceptionCallback(buffer);
|
||||
};
|
||||
|
||||
// Try to make a very descriptive exception, for that we need to malloc a huge buffer...
|
||||
if (auto buffer = (char*)malloc(max_logsize_ever))
|
||||
{
|
||||
Log(buffer, max_logsize_ever, true, true, true);
|
||||
free(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use a static buffer, no need for any allocation
|
||||
static const auto size = max_logsize_basic + max_logsize_regs + max_logsize_stackdump;
|
||||
static char static_buf[size];
|
||||
static_assert(size <= max_static_buffer, "Static buffer is too big");
|
||||
|
||||
Log(buffer = static_buf, sizeof(static_buf), true, true, false);
|
||||
}
|
||||
|
||||
// Continue exception propagation
|
||||
return (PrevFilter ? PrevFilter(pException) : EXCEPTION_CONTINUE_SEARCH); // I'm not really sure about this return
|
||||
}
|
||||
|
||||
/*
|
||||
* InstallExceptionCatcher
|
||||
* Installs a exception handler to call the specified callback when it happens with human readalbe information.
|
||||
*/
|
||||
int InstallExceptionCatcher(void(*cb)(const char* log))
|
||||
{
|
||||
PrevFilter = SetUnhandledExceptionFilter(TheUnhandledExceptionFilter);
|
||||
ExceptionCallback = cb;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* LogException
|
||||
* Takes an LPEXCEPTION_POINTERS and transforms in a string that is put in the logging steam
|
||||
*/
|
||||
static int LogException(char* buffer, size_t max, LPEXCEPTION_POINTERS pException, bool bLogRegisters, bool bLogStack, bool bLogBacktrace)
|
||||
{
|
||||
ExceptionTracer trace(buffer, max, pException);
|
||||
trace.PrintUnhandledException();
|
||||
trace.EnterScope();
|
||||
if (bLogRegisters) trace.PrintRegisters();
|
||||
if (bLogStack) trace.PrintStackdump();
|
||||
if (bLogBacktrace) trace.PrintBacktrace();
|
||||
trace.LeaveScope();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* ExceptionTracer
|
||||
* Contructs a exception trace object, responssible for tracing informations about an exception
|
||||
*/
|
||||
ExceptionTracer::ExceptionTracer(char* buffer, size_t max, LPEXCEPTION_POINTERS pException) :
|
||||
buffer(buffer), exception(*pException), record(*pException->ExceptionRecord), context(*pException->ContextRecord)
|
||||
{
|
||||
this->buffer = buffer;
|
||||
this->buffer[this->len = 0] = 0;
|
||||
this->spc[this->nspc = 0] = 0;
|
||||
this->max = max;
|
||||
|
||||
// Acquiere common information that we'll access
|
||||
this->module = GetModuleFromAddress(record.ExceptionAddress);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print
|
||||
* Prints some formated text into the logging buffer
|
||||
*/
|
||||
void ExceptionTracer::Print(const char* fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
if ((this->max - this->len) > max_chars_per_print)
|
||||
this->len += vsprintf(&this->buffer[len], fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
/*
|
||||
* EnterScope
|
||||
* Enters a new scope in the logging buffer (scope is related to indentation)
|
||||
* This also prints a new line
|
||||
*/
|
||||
void ExceptionTracer::EnterScope()
|
||||
{
|
||||
nspc += 4;
|
||||
spc[nspc - 4] = ' ';
|
||||
spc[nspc - 3] = ' ';
|
||||
spc[nspc - 2] = ' ';
|
||||
spc[nspc - 1] = ' ';
|
||||
spc[nspc - 0] = 0;
|
||||
NewLine();
|
||||
}
|
||||
|
||||
/*
|
||||
* LeaveScope
|
||||
* Leaves the scope
|
||||
*/
|
||||
void ExceptionTracer::LeaveScope()
|
||||
{
|
||||
assert(nspc > 0);
|
||||
nspc -= 4;
|
||||
spc[nspc] = 0;
|
||||
NewLine();
|
||||
}
|
||||
|
||||
/*
|
||||
* PrintUnhandledException
|
||||
* Prints the well known "Unhandled exception at ..." into the logging buffer
|
||||
*/
|
||||
void ExceptionTracer::PrintUnhandledException()
|
||||
{
|
||||
char module_name[MAX_PATH];
|
||||
auto dwExceptionCode = record.ExceptionCode;
|
||||
uintptr_t address = (uintptr_t)record.ExceptionAddress;
|
||||
|
||||
// Find out our module name for logging
|
||||
if (!this->module || !GetModuleFileNameA(this->module, module_name, sizeof(module_name)))
|
||||
strcpy(module_name, "unknown");
|
||||
|
||||
// Log the exception in a similar format similar to debuggers format
|
||||
Print("Unhandled exception at 0x%p in %s", address, FindModuleName(module, module_name, sizeof(module_name)));
|
||||
if (module) Print(" (+0x%x)", address - (uintptr_t)(module));
|
||||
Print(": 0x%X: %s", dwExceptionCode, GetExceptionCodeString(dwExceptionCode));
|
||||
|
||||
// If exception is IN_PAGE_ERROR or ACCESS_VIOLATION, we have additional information such as an address
|
||||
if (dwExceptionCode == EXCEPTION_IN_PAGE_ERROR || dwExceptionCode == EXCEPTION_ACCESS_VIOLATION)
|
||||
{
|
||||
auto rw = (DWORD)record.ExceptionInformation[0]; // read or write?
|
||||
auto addr = (ULONG_PTR)record.ExceptionInformation[1]; // which address?
|
||||
|
||||
Print(" %s 0x%p",
|
||||
rw == 0 ? "reading location" : rw == 1 ? "writing location" : rw == 8 ? "DEP at" : "",
|
||||
addr);
|
||||
|
||||
// IN_PAGE_ERROR have another information...
|
||||
if (dwExceptionCode == EXCEPTION_IN_PAGE_ERROR)
|
||||
{
|
||||
NewLine();
|
||||
Print("Underlying NTSTATUS code that resulted in the exception is 0x%p",
|
||||
record.ExceptionInformation[2]);
|
||||
}
|
||||
}
|
||||
|
||||
Print(".");
|
||||
}
|
||||
|
||||
/*
|
||||
* PrintRegisters
|
||||
* Prints the content of the assembly registers into the logging buffer
|
||||
*/
|
||||
void ExceptionTracer::PrintRegisters()
|
||||
{
|
||||
int regs_in_line = 0; // Amount of registers currently printed on this line
|
||||
|
||||
// Prints a register, followed by spaces
|
||||
auto PrintRegister = [this, ®s_in_line](const char* reg_name, size_t reg_value, const char* spaces)
|
||||
{
|
||||
Print("%s: 0x%p%s", reg_name, reg_value, spaces);
|
||||
if (++regs_in_line >= 4) { this->NewLine(); regs_in_line = 0; }
|
||||
};
|
||||
|
||||
auto PrintFloatRegister = [this, ®s_in_line](const char* reg_name, int reg_num, uint32_t reg_value1, uint32_t reg_value2, uint32_t reg_value3, uint32_t reg_value4)
|
||||
{
|
||||
Print("%s%02d: 0x%08X 0x%08X 0x%08X 0x%08X [ %f %f %f %f ]", reg_name, reg_num, reg_value1, reg_value2, reg_value3, reg_value4,
|
||||
*(float*)& reg_value1, *(float*)& reg_value2, *(float*)& reg_value3, *(float*)& reg_value4);
|
||||
if (++regs_in_line >= 1) { this->NewLine(); regs_in_line = 0; }
|
||||
};
|
||||
|
||||
// Prints a general purposes register
|
||||
auto PrintIntRegister = [PrintRegister](const char* reg_name, size_t reg_value)
|
||||
{
|
||||
PrintRegister(reg_name, reg_value, " ");
|
||||
};
|
||||
|
||||
// Prints a segment register
|
||||
auto PrintSegRegister = [PrintRegister](const char* reg_name, size_t reg_value)
|
||||
{
|
||||
PrintRegister(reg_name, reg_value, " ");
|
||||
};
|
||||
|
||||
Print("Register dump:");
|
||||
EnterScope();
|
||||
{
|
||||
// Print main general purposes registers
|
||||
if (context.ContextFlags & CONTEXT_INTEGER)
|
||||
{
|
||||
#if !_M_X64
|
||||
PrintIntRegister("EAX", context.Eax);
|
||||
PrintIntRegister("EBX", context.Ebx);
|
||||
PrintIntRegister("ECX", context.Ecx);
|
||||
PrintIntRegister("EDX", context.Edx);
|
||||
PrintIntRegister("EDI", context.Edi);
|
||||
PrintIntRegister("ESI", context.Esi);
|
||||
#else
|
||||
PrintIntRegister("RAX", context.Rax);
|
||||
PrintIntRegister("RCX", context.Rcx);
|
||||
PrintIntRegister("RDX", context.Rdx);
|
||||
PrintIntRegister("RBX", context.Rbx);
|
||||
PrintIntRegister("RBP", context.Rbp);
|
||||
PrintIntRegister("RSI", context.Rsi);
|
||||
PrintIntRegister("RDI", context.Rdi);
|
||||
PrintIntRegister("R08", context.R8);
|
||||
PrintIntRegister("R09", context.R9);
|
||||
PrintIntRegister("R10", context.R10);
|
||||
PrintIntRegister("R11", context.R11);
|
||||
PrintIntRegister("R12", context.R12);
|
||||
PrintIntRegister("R13", context.R13);
|
||||
PrintIntRegister("R14", context.R14);
|
||||
PrintIntRegister("R15", context.R15);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Print control registers
|
||||
if (context.ContextFlags & CONTEXT_CONTROL)
|
||||
{
|
||||
#if !_M_X64
|
||||
PrintIntRegister("EBP", context.Ebp);
|
||||
PrintIntRegister("EIP", context.Eip);
|
||||
PrintIntRegister("ESP", context.Esp);
|
||||
PrintIntRegister("EFL", context.EFlags);
|
||||
this->NewLine(); this->NewLine(); regs_in_line = 0;
|
||||
PrintSegRegister("CS", context.SegCs);
|
||||
PrintSegRegister("SS", context.SegSs);
|
||||
#else
|
||||
PrintIntRegister("RIP", context.Rip);
|
||||
PrintIntRegister("RSP", context.Rsp);
|
||||
PrintIntRegister("EFL", context.EFlags);
|
||||
this->NewLine(); this->NewLine(); regs_in_line = 0;
|
||||
PrintSegRegister("CS", context.SegCs);
|
||||
PrintSegRegister("SS", context.SegSs);
|
||||
#endif
|
||||
}
|
||||
|
||||
this->NewLine(); regs_in_line = 0;
|
||||
|
||||
// Print segment registers
|
||||
if (context.ContextFlags & CONTEXT_SEGMENTS)
|
||||
{
|
||||
PrintSegRegister("GS", context.SegGs);
|
||||
PrintSegRegister("FS", context.SegFs);
|
||||
this->NewLine(); regs_in_line = 0;
|
||||
PrintSegRegister("ES", context.SegEs);
|
||||
PrintSegRegister("DS", context.SegDs);
|
||||
}
|
||||
|
||||
this->NewLine(); this->NewLine(); regs_in_line = 0;
|
||||
|
||||
// Print floating point registers
|
||||
if (context.ContextFlags & CONTEXT_FLOATING_POINT)
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
#if !_M_X64
|
||||
auto f = *(M128A*) & (context.FloatSave.RegisterArea[i * 10]);
|
||||
PrintFloatRegister("ST", i, LODWORD(f.Low), HIDWORD(f.Low), LODWORD(f.High), HIDWORD(f.High));
|
||||
#else
|
||||
PrintFloatRegister("ST", i,
|
||||
LODWORD(context.FltSave.FloatRegisters[i].Low), HIDWORD(context.FltSave.FloatRegisters[i].Low),
|
||||
LODWORD(context.FltSave.FloatRegisters[i].High), HIDWORD(context.FltSave.FloatRegisters[i].High));
|
||||
#endif
|
||||
}
|
||||
|
||||
this->NewLine();
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
#if !_M_X64
|
||||
auto f = *(M128A*) & (context.ExtendedRegisters[(i + 10) * 16]);
|
||||
PrintFloatRegister("XMM", i, LODWORD(f.Low), HIDWORD(f.Low), LODWORD(f.High), HIDWORD(f.High));
|
||||
|
||||
if (i >= 7)
|
||||
break;
|
||||
#else
|
||||
PrintFloatRegister("XMM", i,
|
||||
LODWORD(context.FltSave.XmmRegisters[i].Low), HIDWORD(context.FltSave.XmmRegisters[i].Low),
|
||||
LODWORD(context.FltSave.XmmRegisters[i].High), HIDWORD(context.FltSave.XmmRegisters[i].High));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
LeaveScope();
|
||||
}
|
||||
|
||||
/*
|
||||
* PrintStackdump
|
||||
* Prints the content of the stack into the logging buffer
|
||||
*/
|
||||
void ExceptionTracer::PrintStackdump()
|
||||
{
|
||||
// We need the ESP of the exception context to execute a stack dump, make sure we have access to it
|
||||
if ((context.ContextFlags & CONTEXT_CONTROL) == 0)
|
||||
return;
|
||||
|
||||
static const auto align = sizeof_word; // Stack aligment
|
||||
static const auto max_words_in_line_magic = stackdump_words_per_line + 10;
|
||||
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
#if !_M_X64
|
||||
uintptr_t base, bottom, top = (uintptr_t)context.Esp;
|
||||
#else
|
||||
uintptr_t base, bottom, top = (uintptr_t)context.Rsp;
|
||||
#endif
|
||||
auto words_in_line = max_words_in_line_magic;
|
||||
|
||||
// Finds the bottom of the stack from it's base pointer
|
||||
// Note: mbi will get overriden on this function
|
||||
auto GetStackBottom = [&mbi](uintptr_t base)
|
||||
{
|
||||
VirtualQuery((void*)base, &mbi, sizeof(mbi)); // Find uncommited region of the stack
|
||||
VirtualQuery((char*)mbi.BaseAddress + mbi.RegionSize, &mbi, sizeof(mbi)); // Find guard page
|
||||
VirtualQuery((char*)mbi.BaseAddress + mbi.RegionSize, &mbi, sizeof(mbi)); // Find commited region of the stack
|
||||
auto last = (uintptr_t)mbi.BaseAddress;
|
||||
return (base + (last - base) + mbi.RegionSize); // base + distanceToLastRegion + lastRegionSize
|
||||
};
|
||||
|
||||
// Prints an CPU word at the specified stack address
|
||||
auto PrintWord = [this, &words_in_line](uintptr_t addr)
|
||||
{
|
||||
if (words_in_line++ >= stackdump_words_per_line)
|
||||
{
|
||||
// Print new line only if it's not the first time we enter here (i.e. words_in_line has magical value)
|
||||
if (words_in_line != max_words_in_line_magic + 1) NewLine();
|
||||
words_in_line = 1;
|
||||
Print("0x%p: ", addr);
|
||||
}
|
||||
Print(" %p", *(size_t*)addr);
|
||||
};
|
||||
|
||||
Print("Stack dump:");
|
||||
EnterScope();
|
||||
{
|
||||
// Makes sure the pointer at top (ESP) is valid and readable memory
|
||||
if (VirtualQuery((void*)(top), &mbi, sizeof(mbi))
|
||||
&& (mbi.State & MEM_COMMIT)
|
||||
&& (mbi.Protect & (PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_READWRITE | PAGE_READONLY)) != 0)
|
||||
{
|
||||
base = (uintptr_t)mbi.AllocationBase; // Base of the stack (uncommited)
|
||||
bottom = GetStackBottom(base); // Bottom of the stack (commited)
|
||||
|
||||
// Align the stack top (esp) in a 4 bytes boundary
|
||||
auto remainder = top % align;
|
||||
uintptr_t current = remainder ? top + (align - remainder) : top;
|
||||
|
||||
// on x86 stack grows downward! (i.e. from bottom to base)
|
||||
for (int n = 0; n < stackdump_max_words && current < bottom; ++n, current += align)
|
||||
PrintWord(current);
|
||||
|
||||
NewLine();
|
||||
Print("base: 0x%p top: 0x%p bottom: 0x%p", base, top, bottom);
|
||||
NewLine();
|
||||
}
|
||||
}
|
||||
LeaveScope();
|
||||
}
|
||||
|
||||
/*
|
||||
* PrintBacktrace
|
||||
* Prints a call backtrace into the logging buffer
|
||||
*/
|
||||
void ExceptionTracer::PrintBacktrace()
|
||||
{
|
||||
StackTracer tracer(this->context);
|
||||
|
||||
char module_name[MAX_PATH];
|
||||
char sym_buffer[sizeof(SYMBOL_INFO) + symbol_max];
|
||||
|
||||
int backtrace_count = 0; // Num of frames traced
|
||||
bool has_symbol_api = false; // True if we have the symbol API available for use
|
||||
DWORD old_options; // Saves old symbol API options
|
||||
|
||||
SYMBOL_INFO& symbol = *(SYMBOL_INFO*)sym_buffer;
|
||||
symbol.SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
symbol.MaxNameLen = symbol_max;
|
||||
|
||||
// Tries to get the symbol api
|
||||
if (SymInitialize(GetCurrentProcess(), 0, TRUE))
|
||||
{
|
||||
has_symbol_api = true;
|
||||
old_options = SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES | SYMOPT_NO_PROMPTS | SYMOPT_FAIL_CRITICAL_ERRORS);
|
||||
}
|
||||
|
||||
Print("Backtrace (may be wrong):");
|
||||
EnterScope();
|
||||
{
|
||||
// Walks on the stack until there's no frame to trace or we traced 'max_backtrace' frames
|
||||
while (auto trace = tracer.Walk())
|
||||
{
|
||||
if (++backtrace_count >= max_backtrace)
|
||||
break;
|
||||
|
||||
bool has_sym = false; // This EIP has a symbol associated with it?
|
||||
DWORD64 displacement; // EIP displacement relative to symbol
|
||||
|
||||
// If we have access to the symbol api, try to get symbol name from pc (eip)
|
||||
if (has_symbol_api)
|
||||
has_sym = trace->pc ? !!SymFromAddr(GetCurrentProcess(), (DWORD64)trace->pc, &displacement, &symbol) : false;
|
||||
|
||||
// Print everything up, this.... Ew, this looks awful!
|
||||
Print(backtrace_count == 1 ? "=>" : " "); // First line should have '=>' to specify where it crashed
|
||||
Print("0x%p ", trace->pc); // Print EIP at frame
|
||||
if (has_sym) Print("%s+0x%x ", symbol.Name, (DWORD)displacement); // Print frame func symbol
|
||||
Print("in %s (+0x%x) ", // Print module
|
||||
trace->module ? FindModuleName(trace->module, module_name, sizeof(module_name)) : "unknown",
|
||||
(uintptr_t)(trace->pc) - (uintptr_t)(trace->module) // Module displacement
|
||||
);
|
||||
if (trace->frame) Print("(0x%p) ", trace->frame); // Print frame pointer
|
||||
|
||||
NewLine();
|
||||
}
|
||||
}
|
||||
LeaveScope();
|
||||
|
||||
// Cleanup the symbol api
|
||||
if (has_symbol_api)
|
||||
{
|
||||
SymSetOptions(old_options);
|
||||
SymCleanup(GetCurrentProcess());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* GetExceptionCodeString
|
||||
* Returns an description by an exception code
|
||||
*/
|
||||
static const char* GetExceptionCodeString(unsigned int code)
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case EXCEPTION_ACCESS_VIOLATION: return "Access violation";
|
||||
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return "Array bounds exceeded";
|
||||
case EXCEPTION_BREAKPOINT: return "Breakpoint exception";
|
||||
case EXCEPTION_DATATYPE_MISALIGNMENT: return "Data type misalignment exception";
|
||||
case EXCEPTION_FLT_DENORMAL_OPERAND: return "Denormal float operand";
|
||||
case EXCEPTION_FLT_DIVIDE_BY_ZERO: return "Floating-point division by zero";
|
||||
case EXCEPTION_FLT_INEXACT_RESULT: return "Floating-point inexact result";
|
||||
case EXCEPTION_FLT_INVALID_OPERATION: return "Floating-point invalid operation";
|
||||
case EXCEPTION_FLT_OVERFLOW: return "Floating-point overflow";
|
||||
case EXCEPTION_FLT_STACK_CHECK: return "Floating-point stack check";
|
||||
case EXCEPTION_FLT_UNDERFLOW: return "Floating-point underflow";
|
||||
case EXCEPTION_ILLEGAL_INSTRUCTION: return "Illegal instruction.";
|
||||
case EXCEPTION_IN_PAGE_ERROR: return "In page error";
|
||||
case EXCEPTION_INT_DIVIDE_BY_ZERO: return "Integer division by zero";
|
||||
case EXCEPTION_INT_OVERFLOW: return "Integer overflow";
|
||||
case EXCEPTION_INVALID_DISPOSITION: return "Invalid disposition";
|
||||
case EXCEPTION_NONCONTINUABLE_EXCEPTION: return "Non-continuable exception";
|
||||
case EXCEPTION_PRIV_INSTRUCTION: return "Privileged instruction";
|
||||
case EXCEPTION_SINGLE_STEP: return "Single step exception";
|
||||
case EXCEPTION_STACK_OVERFLOW: return "Stack overflow";
|
||||
default: return "NO_DESCRIPTION";
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* FindModuleName
|
||||
* Finds module filename or "unknown"
|
||||
*/
|
||||
static const char* FindModuleName(HMODULE module, char* output, DWORD maxsize)
|
||||
{
|
||||
if (GetModuleFileNameA(module, output, maxsize))
|
||||
{
|
||||
// Finds the filename part in the output string
|
||||
char* filename = strrchr(output, '\\');
|
||||
if (!filename) filename = strrchr(output, '/');
|
||||
|
||||
// If filename found (i.e. output isn't already a filename but full path), make output be filename
|
||||
if (filename)
|
||||
{
|
||||
size_t size = strlen(++filename);
|
||||
memmove(output, filename, size);
|
||||
output[size] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unknown module
|
||||
strcpy(output, "unknown");
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
/*
|
||||
* GetModuleFromAddress
|
||||
* Finds module handle from some address inside it
|
||||
*/
|
||||
static HMODULE GetModuleFromAddress(LPVOID address)
|
||||
{
|
||||
HMODULE module;
|
||||
if (GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
|
||||
(char*)address, &module))
|
||||
return module;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* StackTracer
|
||||
* Constructs the tracer, we basically need to initialize the symbol api
|
||||
*/
|
||||
StackTracer::StackTracer(const CONTEXT& context)
|
||||
{
|
||||
// Initialise basic values
|
||||
memset(&this->frame, 0, sizeof(frame));
|
||||
memcpy(&this->context, &context, sizeof(context));
|
||||
|
||||
// Setup the initial frame context
|
||||
#if !_M_X64
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrPC.Offset = context.Eip;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Offset = context.Ebp;
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
frame.AddrStack.Offset = context.Esp;
|
||||
#else
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrPC.Offset = context.Rip;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Offset = context.Rbp;
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
frame.AddrStack.Offset = context.Rsp;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* StackTracer::Walk
|
||||
* Walks on the stack, each walk is one frame of backtrace
|
||||
* Returns a frame or null if the walk on the park is not possible anymore
|
||||
*/
|
||||
StackTracer::Trace* StackTracer::Walk()
|
||||
{
|
||||
if (StackWalk64(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), GetCurrentThread(),
|
||||
&frame, &context, NULL, NULL, NULL, NULL))
|
||||
{
|
||||
trace.module = GetModuleFromAddress((void*)frame.AddrPC.Offset);
|
||||
trace.frame = (void*)frame.AddrFrame.Offset;
|
||||
trace.stack = (void*)frame.AddrStack.Offset;
|
||||
trace.pc = (void*)frame.AddrPC.Offset;
|
||||
trace.ret = (void*)frame.AddrReturn.Offset;
|
||||
return &trace;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
// Windows Header Files
|
||||
#include <windows.h>
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <shlobj.h>
|
||||
#include <set>
|
||||
#include "ModuleList.h"
|
||||
#include <intrin.h>
|
||||
#pragma intrinsic(_ReturnAddress)
|
||||
|
||||
struct shared
|
||||
{
|
||||
FARPROC DllCanUnloadNow;
|
||||
FARPROC DllGetClassObject;
|
||||
FARPROC DllRegisterServer;
|
||||
FARPROC DllUnregisterServer;
|
||||
FARPROC DebugSetMute;
|
||||
|
||||
void LoadOriginalLibrary(HMODULE dll)
|
||||
{
|
||||
DllCanUnloadNow = GetProcAddress(dll, "DllCanUnloadNow");
|
||||
DllGetClassObject = GetProcAddress(dll, "DllGetClassObject");
|
||||
DllRegisterServer = GetProcAddress(dll, "DllRegisterServer");
|
||||
DllUnregisterServer = GetProcAddress(dll, "DllUnregisterServer");
|
||||
DebugSetMute = GetProcAddress(dll, "DebugSetMute");
|
||||
}
|
||||
} shared;
|
||||
|
||||
struct dnsapi_dll
|
||||
{
|
||||
HMODULE dll;
|
||||
|
||||
// only some functions are implemented.
|
||||
// PDAFT doesn't use many, so this should hopefully be fine
|
||||
FARPROC DnsFree;
|
||||
FARPROC DnsQuery_A;
|
||||
FARPROC DnsQueryEx;
|
||||
FARPROC DnsCancelQuery;
|
||||
|
||||
// DnsQueryEx and DnsCancelQuery take pointers to structs as parameters
|
||||
// (three for DnsQueryEx and one for DnsCancelQuery)
|
||||
// fortunately they should fit in registers so the stack doesn't matter
|
||||
// hopefully this works fine... I have no clue what I'm doing
|
||||
static LONG WINAPI DnsQueryExStub()
|
||||
{
|
||||
return 9004; // DNS_ERROR_RCODE_NOT_IMPLEMENTED
|
||||
}
|
||||
static LONG WINAPI DnsCancelQueryStub()
|
||||
{
|
||||
return 9004; // DNS_ERROR_RCODE_NOT_IMPLEMENTED
|
||||
}
|
||||
|
||||
void LoadOriginalLibrary(HMODULE module)
|
||||
{
|
||||
dll = module;
|
||||
shared.LoadOriginalLibrary(dll);
|
||||
DnsFree = GetProcAddress(dll, "DnsFree");
|
||||
DnsQuery_A = GetProcAddress(dll, "DnsQuery_A");
|
||||
DnsQueryEx = GetProcAddress(dll, "DnsQueryEx");
|
||||
DnsCancelQuery = GetProcAddress(dll, "DnsCancelQuery");
|
||||
|
||||
// if entry points aren't found, GetProcAddress should return null
|
||||
// I hope this is correct
|
||||
// Thanks to somewhatlurker
|
||||
if (DnsQueryEx == NULL) { DnsQueryEx = (FARPROC)& DnsQueryExStub; };
|
||||
if (DnsCancelQuery == NULL) { DnsCancelQuery = (FARPROC)& DnsCancelQueryStub; };
|
||||
}
|
||||
} dnsapi;
|
||||
|
||||
void _DnsFree() { dnsapi.DnsFree(); }
|
||||
void _DnsQuery_A() { dnsapi.DnsQuery_A(); }
|
||||
void _DnsQueryEx() { dnsapi.DnsQueryEx(); }
|
||||
void _DnsCancelQuery() { dnsapi.DnsCancelQuery(); }
|
||||
|
||||
#pragma runtime_checks( "", off )
|
||||
|
||||
#ifdef _DEBUG
|
||||
#pragma message ("You are compiling the code in Debug - be warned that wrappers for export functions may not have correct code generated")
|
||||
#endif
|
||||
|
||||
void _DllRegisterServer() { shared.DllRegisterServer(); }
|
||||
void _DllUnregisterServer() { shared.DllUnregisterServer(); }
|
||||
void _DllCanUnloadNow() { shared.DllCanUnloadNow(); }
|
||||
void _DllGetClassObject() { shared.DllGetClassObject(); }
|
||||
|
||||
#pragma runtime_checks( "", restore )
|
||||
@@ -0,0 +1,10 @@
|
||||
LIBRARY "dnsapi"
|
||||
EXPORTS
|
||||
DnsFree = _DnsFree
|
||||
DnsQuery_A = _DnsQuery_A
|
||||
DnsQueryEx = _DnsQueryEx
|
||||
DnsCancelQuery = _DnsCancelQuery
|
||||
DllCanUnloadNow = _DllCanUnloadNow PRIVATE
|
||||
DllGetClassObject = _DllGetClassObject PRIVATE
|
||||
DllRegisterServer = _DllRegisterServer PRIVATE
|
||||
DllUnregisterServer = _DllUnregisterServer PRIVATE
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ui.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="constants.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,182 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<ProjectGuid>{60d5e9f4-335f-402b-9a07-d78674dffc9b}</ProjectGuid>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<Keyword>ManagedCProj</Keyword>
|
||||
<RootNamespace>Launcher</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>Launcher</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CLRSupport>true</CLRSupport>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CLRSupport>true</CLRSupport>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CLRSupport>true</CLRSupport>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CLRSupport>true</CLRSupport>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<TargetExt>.dva</TargetExt>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<TargetExt>.dva</TargetExt>
|
||||
<TargetName>$(ProjectName)</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies />
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EntryPointSymbol>main</EntryPointSymbol>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>
|
||||
</PrecompiledHeaderFile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\..\..\dependencies\detours\include;..\..\..\dependencies\freeglut\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>User32.lib</AdditionalDependencies>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EntryPointSymbol>
|
||||
</EntryPointSymbol>
|
||||
<AdditionalLibraryDirectories>..\..\..\dependencies\detours\lib;..\..\..\dependencies\freeglut\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies />
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EntryPointSymbol>main</EntryPointSymbol>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>
|
||||
</PrecompiledHeaderFile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\..\..\dependencies\detours\include;..\..\..\dependencies\freeglut\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>User32.lib</AdditionalDependencies>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EntryPointSymbol>
|
||||
</EntryPointSymbol>
|
||||
<AdditionalLibraryDirectories>..\..\..\dependencies\detours\lib;..\..\..\dependencies\freeglut\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
<ClCompile Include="TabPadding.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="framework.h" />
|
||||
<ClInclude Include="TabPadding.h" />
|
||||
<ClInclude Include="ui.h">
|
||||
<FileType>CppForm</FileType>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="ui.resx">
|
||||
<DependentUpon>ui.h</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,44 @@
|
||||
#include "TabPadding.h"
|
||||
//#include <Windows.h>
|
||||
|
||||
// ported from https://stackoverflow.com/a/7785745
|
||||
// original code by user LarsTech https://stackoverflow.com/users/719186/larstech
|
||||
|
||||
TabPadding::TabPadding(TabControl^ tc)
|
||||
{
|
||||
tabControl = tc;
|
||||
tabControl->Selected += gcnew TabControlEventHandler(this, &TabPadding::tabControl_Selected);
|
||||
AssignHandle(tc->Handle);
|
||||
}
|
||||
|
||||
void TabPadding::tabControl_Selected(Object^ sender, TabControlEventArgs^ e)
|
||||
{
|
||||
tabControl->Invalidate();
|
||||
}
|
||||
|
||||
void TabPadding::WndProc(Message %m) {
|
||||
NativeWindow::WndProc(m);
|
||||
|
||||
if (m.Msg == 15) { //WM_PAINT
|
||||
Graphics^ g = Graphics::FromHwnd(m.HWnd);
|
||||
|
||||
//Replace the outside white borders:
|
||||
if (tabControl->Parent) {
|
||||
g->SetClip(System::Drawing::Rectangle(0, 0, tabControl->Width - 2, tabControl->Height - 1), Drawing2D::CombineMode::Exclude);
|
||||
g->FillRectangle(gcnew SolidBrush(tabControl->Parent->BackColor),
|
||||
System::Drawing::Rectangle(0, tabControl->ItemSize.Height + 2, tabControl->Width, tabControl->Height - (tabControl->ItemSize.Height + 2)));
|
||||
}
|
||||
|
||||
|
||||
//Replace the inside white borders:
|
||||
if (tabControl->SelectedTab) {
|
||||
g->ResetClip();
|
||||
System::Drawing::Rectangle r = tabControl->SelectedTab->Bounds;
|
||||
g->SetClip(r, Drawing2D::CombineMode::Exclude);
|
||||
g->FillRectangle(gcnew SolidBrush(tabControl->SelectedTab->BackColor),
|
||||
System::Drawing::Rectangle(r.Left - 3, r.Top - 1, r.Width + 4, r.Height + 3));
|
||||
}
|
||||
|
||||
delete g;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
using namespace System::Windows::Forms;
|
||||
using namespace System::Drawing;
|
||||
|
||||
// ported from https://stackoverflow.com/a/7785745
|
||||
// original code by user LarsTech https://stackoverflow.com/users/719186/larstech
|
||||
|
||||
ref class TabPadding : public NativeWindow
|
||||
{
|
||||
public:
|
||||
TabPadding(TabControl^ tc);
|
||||
|
||||
private:
|
||||
TabControl^ tabControl;
|
||||
void tabControl_Selected(Object^ sender, TabControlEventArgs^ e);
|
||||
|
||||
protected:
|
||||
virtual void WndProc(Message %m) override;
|
||||
};
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 229 KiB |
@@ -0,0 +1,45 @@
|
||||
#include "ui.h"
|
||||
#include "framework.h"
|
||||
#include <detours.h>
|
||||
#pragma comment(lib, "detours.lib")
|
||||
|
||||
using namespace System;
|
||||
using namespace System::Windows::Forms;
|
||||
|
||||
[STAThread]
|
||||
int showUI() {
|
||||
if (Environment::OSVersion->Version->Major >= 6)
|
||||
SetProcessDPIAware();
|
||||
|
||||
Application::EnableVisualStyles();
|
||||
Application::SetCompatibleTextRenderingDefault(false);
|
||||
Application::Run(gcnew Launcher::ui());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hookedMain(int argc, const char** argv, const char** envp)
|
||||
{
|
||||
for (int i = 0; i < argc; ++i)
|
||||
{
|
||||
arg = argv[i];
|
||||
if (arg == "--launch" || nSkipLauncher)
|
||||
return divaMain(argc, argv, envp);
|
||||
}
|
||||
return showUI();
|
||||
}
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule,
|
||||
DWORD ul_reason_for_call,
|
||||
LPVOID lpReserved
|
||||
)
|
||||
{
|
||||
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
|
||||
{
|
||||
DisableThreadLibraryCalls(hModule);
|
||||
DetourTransactionBegin();
|
||||
DetourUpdateThread(GetCurrentThread());
|
||||
DetourAttach(&(PVOID&)divaMain, hookedMain);
|
||||
DetourTransactionCommit();
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
// Windows Header Files
|
||||
#include <windows.h>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
|
||||
int (__cdecl* divaMain)(int argc, const char** argv, const char** envp) = (int(__cdecl*)(int argc, const char** argv, const char** envp))0x140194D90;
|
||||
|
||||
using namespace std;
|
||||
|
||||
string arg;
|
||||
|
||||
wstring ExePath() {
|
||||
WCHAR buffer[MAX_PATH];
|
||||
GetModuleFileNameW(NULL, buffer, MAX_PATH);
|
||||
return wstring(buffer);
|
||||
}
|
||||
|
||||
wstring DirPath() {
|
||||
wstring exepath = ExePath();
|
||||
wstring::size_type pos = exepath.find_last_of(L"\\/");
|
||||
return exepath.substr(0, pos);
|
||||
}
|
||||
|
||||
wstring DIVA_EXECUTABLE_STRING = ExePath();
|
||||
LPCWSTR DIVA_EXECUTABLE = DIVA_EXECUTABLE_STRING.c_str();
|
||||
|
||||
wstring DIVA_EXECUTABLE_LAUNCH_STRING = DIVA_EXECUTABLE_STRING + L" --launch";
|
||||
LPWSTR DIVA_EXECUTABLE_LAUNCH = const_cast<WCHAR*>(DIVA_EXECUTABLE_LAUNCH_STRING.c_str());
|
||||
|
||||
wstring CONFIG_FILE_STRING = DirPath() + L"\\plugins\\config.ini";
|
||||
LPCWSTR CONFIG_FILE = CONFIG_FILE_STRING.c_str();
|
||||
|
||||
wstring COMPONENTS_FILE_STRING = DirPath() + L"\\plugins\\components.ini";
|
||||
LPCWSTR COMPONENTS_FILE = COMPONENTS_FILE_STRING.c_str();
|
||||
|
||||
int nDisplay = GetPrivateProfileIntW(L"resolution", L"display", 0, CONFIG_FILE);
|
||||
int nWidth = GetPrivateProfileIntW(L"resolution", L"width", 1280, CONFIG_FILE);
|
||||
int nHeight = GetPrivateProfileIntW(L"resolution", L"height", 720, CONFIG_FILE);
|
||||
|
||||
int nIntRes = GetPrivateProfileIntW(L"resolution", L"r.enable", FALSE, CONFIG_FILE);
|
||||
int nIntResWidth = GetPrivateProfileIntW(L"resolution", L"r.width", 1280, CONFIG_FILE);
|
||||
int nIntResHeight = GetPrivateProfileIntW(L"resolution", L"r.height", 720, CONFIG_FILE);
|
||||
|
||||
int nBitDepth = GetPrivateProfileIntW(L"resolution", L"bitdepth", 32, CONFIG_FILE);
|
||||
int nRefreshRate = GetPrivateProfileIntW(L"resolution", L"refreshrate", 60, CONFIG_FILE);
|
||||
|
||||
int nCursor = GetPrivateProfileIntW(L"patches", L"cursor", TRUE, CONFIG_FILE);
|
||||
int nHideFreeplay = GetPrivateProfileIntW(L"patches", L"hide_freeplay", FALSE, CONFIG_FILE);
|
||||
int nStatusIcons = GetPrivateProfileIntW(L"patches", L"status_icons", 0, CONFIG_FILE);
|
||||
int nHidePVWatermark = GetPrivateProfileIntW(L"patches", L"hide_pv_watermark", FALSE, CONFIG_FILE);
|
||||
int nNoPVUi = GetPrivateProfileIntW(L"patches", L"no_pv_ui", FALSE, CONFIG_FILE);
|
||||
int nHideVolCtrl = GetPrivateProfileIntW(L"patches", L"hide_volume", FALSE, CONFIG_FILE);
|
||||
int nNoLyrics = GetPrivateProfileIntW(L"patches", L"no_lyrics", FALSE, CONFIG_FILE);
|
||||
int nNoMovies = GetPrivateProfileIntW(L"patches", L"no_movies", FALSE, CONFIG_FILE);
|
||||
int nNoError = GetPrivateProfileIntW(L"patches", L"no_error", TRUE, CONFIG_FILE);
|
||||
|
||||
int nTAA = GetPrivateProfileIntW(L"graphics", L"TAA", TRUE, CONFIG_FILE);
|
||||
int nMLAA = GetPrivateProfileIntW(L"graphics", L"MLAA", TRUE, CONFIG_FILE);
|
||||
int nFPSLimit = GetPrivateProfileIntW(L"graphics", L"FPS.Limit", 0, CONFIG_FILE);
|
||||
|
||||
int nSkipLauncher = GetPrivateProfileIntW(L"launcher", L"skip", FALSE, CONFIG_FILE);
|
||||
|
||||
|
||||
// Custom function. Works like GetPrivateProfileIntW but returns bool. Can detect a numeric value or string.
|
||||
bool GetPrivateProfileBoolW(LPCWSTR lpAppName, LPCWSTR lpKeyName, bool default, LPCWSTR lpFileName)
|
||||
{
|
||||
wchar_t buffer[8];
|
||||
GetPrivateProfileStringW(lpAppName, lpKeyName, L"", buffer, 8, lpFileName);
|
||||
//MessageBoxW(NULL, buffer, NULL, 0);
|
||||
|
||||
for (wchar_t& chr : buffer)
|
||||
chr = towlower(chr);
|
||||
|
||||
bool out;
|
||||
if ((lstrcmpW(buffer, L"true") == 0) || (lstrcmpW(buffer, L"1") == 0))
|
||||
out = true;
|
||||
else if ((lstrcmpW(buffer, L"false") == 0) || (lstrcmpW(buffer, L"0") == 0))
|
||||
out = false;
|
||||
else
|
||||
out = default;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
struct componentInfo { const LPCWSTR name; LPCWSTR friendlyName; LPCWSTR description; System::IntPtr cb; };
|
||||
componentInfo componentsArray[] = {
|
||||
{ L"input_emulator", L"Input Emulator", L"Emulates input through keyboard and/or mouse.", System::IntPtr::Zero },
|
||||
{ L"touch_slider_emulator", L"Slider Emulator", L"Emulates slider through keyboard and/or mouse.", System::IntPtr::Zero },
|
||||
{ L"touch_panel_emulator", L"Touch Panel Emulator", L"Emulates touch panel through mouse.", System::IntPtr::Zero },
|
||||
|
||||
{ L"sys_timer", L"Timer Freeze", L"Freezes the PV select timer at 39 seconds.", System::IntPtr::Zero },
|
||||
|
||||
{ L"player_data_manager", L"Player Data Manager", L"Loads user-defined values into the PlayerData struct.\nRequired for modules and game mode modifiers.", System::IntPtr::Zero },
|
||||
|
||||
{ L"frame_rate_manager", L"Frame Rate Manager", L"Adjusts animations to the correct speed at different frame rates.\nOnly needed when FPS isn't locket at 60.", System::IntPtr::Zero },
|
||||
|
||||
{ L"stage_manager", L"Stage Manager", L"Allows for playing unlimited songs per session.", System::IntPtr::Zero },
|
||||
|
||||
{ L"fast_loader", L"Fast Loader", L"Skip or speed up unnecessary loading steps.", System::IntPtr::Zero },
|
||||
|
||||
{ L"camera_controller", L"Camera Controller", L"Enables freecam (toggled using F3).\nWASD to move, SPACE/CTRL for up/down, Q/R to rotate, R/F for zoom.\nHolding SHIFT/ALT changes control speed.", System::IntPtr::Zero },
|
||||
|
||||
{ L"scale_component", L"Scale Component", L"Scales the graphics output framebuffer to fill the screen/window.", System::IntPtr::Zero },
|
||||
|
||||
{ L"debug_component", L"Debug Component", L"Allows for changing game state (F4-F8 keys), using dev GUI and tests, and speeding up 2d animations/menus (hold SHIFT+TAB).", System::IntPtr::Zero },
|
||||
|
||||
{ L"fps_limiter", L"FPS Limiter", L"Lets you set a framerate cap. The value of the limit is in the options tab.", System::IntPtr::Zero },
|
||||
|
||||
{ L"target_inspector", L"Target Inspector", L"Enables hold transfers.", System::IntPtr::Zero },
|
||||
};
|
||||
|
||||
bool IsLineInFile(LPCSTR searchLine, LPCWSTR fileName)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
std::ifstream fileStream(fileName);
|
||||
|
||||
if (!fileStream.is_open())
|
||||
return false;
|
||||
|
||||
std::string line;
|
||||
|
||||
while (std::getline(fileStream, line))
|
||||
{
|
||||
if (line.compare(searchLine) == 0)
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fileStream.close();
|
||||
return result;
|
||||
}
|
||||
|
||||
void PrependFile(LPCSTR newStr, LPCWSTR fileName)
|
||||
{
|
||||
std::fstream fileStream(fileName);
|
||||
|
||||
if (!fileStream.is_open())
|
||||
return;
|
||||
|
||||
|
||||
std::string origStr;
|
||||
|
||||
// this is apparently more efficient than just going straight into the string
|
||||
fileStream.seekg(0, std::ios::end);
|
||||
origStr.reserve(fileStream.tellg());
|
||||
fileStream.seekg(0, std::ios::beg);
|
||||
origStr.assign((std::istreambuf_iterator<char>(fileStream)), std::istreambuf_iterator<char>());
|
||||
|
||||
std::string outStr = newStr;
|
||||
outStr += origStr;
|
||||
|
||||
fileStream.seekg(0, std::ios::beg);
|
||||
fileStream << outStr;
|
||||
fileStream.close();
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,172 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<ProjectGuid>{3FD6ACA9-E613-4FD6-BDA2-55A91C2CF65C}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>Patches</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<TargetExt>.dva</TargetExt>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<TargetExt>.dva</TargetExt>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;PATCHES_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>..\..\..\dependencies\freeglut\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<AdditionalLibraryDirectories>..\..\..\dependencies\freeglut\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;PATCHES_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;PATCHES_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>
|
||||
</PrecompiledHeaderFile>
|
||||
<AdditionalIncludeDirectories>..\..\..\dependencies\freeglut\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<AdditionalLibraryDirectories>..\..\..\dependencies\freeglut\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;PATCHES_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,248 @@
|
||||
#include "windows.h"
|
||||
#include "vector"
|
||||
#include <tchar.h>
|
||||
#include <GL/freeglut.h>
|
||||
|
||||
void InjectCode(void* address, const std::vector<uint8_t> data);
|
||||
void ApplyPatches();
|
||||
|
||||
const LPCWSTR CONFIG_FILE = L".\\config.ini";
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule,
|
||||
DWORD ul_reason_for_call,
|
||||
LPVOID lpReserved
|
||||
)
|
||||
{
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
ApplyPatches();
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void ApplyPatches() {
|
||||
|
||||
const struct { void* Address; std::vector<uint8_t> Data; } patches[] =
|
||||
{
|
||||
// Always return true for the SelCredit enter SelPv check
|
||||
{ (void*)0x0000000140393610, { 0xB0, 0x01, 0xC3, 0x90, 0x90, 0x90 } },
|
||||
// Just completely ignore all SYSTEM_STARTUP errors
|
||||
{ (void*)0x00000001403F5080, { 0xC3 } },
|
||||
// Always exit TASK_MODE_APP_ERROR on the first frame
|
||||
{ (void*)0x00000001403F73A7, { 0x90, 0x90 } },
|
||||
{ (void*)0x00000001403F73C3, { 0x89, 0xD1, 0x90 } },
|
||||
// Ignore the EngineClear variable to clear the framebuffer at all resolutions
|
||||
{ (void*)0x0000000140501480, { 0x90, 0x90 } },
|
||||
{ (void*)0x0000000140501515, { 0x90, 0x90 } },
|
||||
// Don't update the touch slider state so we can write our own
|
||||
{ (void*)0x000000014061579B, { 0x90, 0x90, 0x90, 0x8B, 0x42, 0xE0, 0x90, 0x90, 0x90 } },
|
||||
// Write ram files to the current directory instead of Y : / SBZV / ram
|
||||
{ (void*)0x000000014066CF09, { 0xE9, 0xD8, 0x00 } },
|
||||
// Change mdata path from "C:/Mount/Option" to "mdata/"
|
||||
{ (void*)0x0000000140A8CA18, { 0x6D, 0x64, 0x61, 0x74, 0x61, 0x2F, 0x00 } },
|
||||
{ (void*)0x000000014066CEAE, { 0x06 } },
|
||||
// Skip parts of the network check state
|
||||
{ (void*)0x00000001406717B1, { 0xE9, 0x22, 0x03, 0x00 } },
|
||||
// Set the initial DHCP WAIT timer value to 0
|
||||
{ (void*)0x00000001406724E7, { 0x00, 0x00 } },
|
||||
// Ignore SYSTEM_STARTUP Location Server checks
|
||||
{ (void*)0x00000001406732A2, { 0x90, 0x90 } },
|
||||
// Toon Shader Fix by lybxlpsv
|
||||
{ (void*)0x000000014050214F, { 0x90 } },
|
||||
{ (void*)0x0000000140502150, { 0x90 } },
|
||||
// Toon Shader Outline Fix by lybxlpsv
|
||||
{ (void*)0x0000000140641102, { 0x01 } },
|
||||
// Skip unnecessary checks
|
||||
{ (void*)0x0000000140210820, { 0xB8, 0x00, 0x00, 0x00, 0x00, 0xC3 } },
|
||||
{ (void*)0x000000014066E820, { 0xB8, 0x01, 0x00, 0x00, 0x00, 0xC3 } },
|
||||
// Disables call to glutFitWindowSizeToDesktop, prevents window automatic resize
|
||||
{ (void*)0x0000000140194E06, { 0x90, 0x90, 0x90, 0x90, 0x90 } },
|
||||
// Allow modifier mode selection (by Team Shimapan)
|
||||
{ (void*)0x00000001405CB1B3, { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } },
|
||||
{ (void*)0x00000001405CA0F5, { 0x90, 0x90 } },
|
||||
// allow modifier modes to work without use_card
|
||||
{ (void*)0x00000001405CB14A,{ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } },
|
||||
{ (void*)0x0000000140136CFA,{ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } },
|
||||
// enable module selector without use_card
|
||||
{ (void*)0x00000001405C513B, { 0x01 } },
|
||||
// Show Freeplay instead
|
||||
{ (void*)0x00000001403BABEA, { 0x75 } },
|
||||
// Force Hide IDs
|
||||
{ (void*)0x00000001409A5918, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
|
||||
{ (void*)0x00000001409A5928, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }
|
||||
};
|
||||
printf("[Patches] Patches loaded\n");
|
||||
|
||||
for (size_t i = 0; i < _countof(patches); i++)
|
||||
InjectCode(patches[i].Address, patches[i].Data);
|
||||
|
||||
auto nCursor = GetPrivateProfileIntW(L"patches", L"cursor", TRUE, CONFIG_FILE);
|
||||
auto nHideFreeplay = GetPrivateProfileIntW(L"patches", L"hide_freeplay", FALSE, CONFIG_FILE);
|
||||
auto nStatusIcons = GetPrivateProfileIntW(L"patches", L"status_icons", 0, CONFIG_FILE);
|
||||
auto nHidePVWatermark = GetPrivateProfileIntW(L"patches", L"hide_pv_watermark", FALSE, CONFIG_FILE);
|
||||
auto nNoPVUi = GetPrivateProfileIntW(L"patches", L"no_pv_ui", FALSE, CONFIG_FILE);
|
||||
auto nHideVolCtrl = GetPrivateProfileIntW(L"patches", L"hide_volume", FALSE, CONFIG_FILE);
|
||||
auto nNoLyrics = GetPrivateProfileIntW(L"patches", L"no_lyrics", FALSE, CONFIG_FILE);
|
||||
auto nNoMovies = GetPrivateProfileIntW(L"patches", L"no_movies", FALSE, CONFIG_FILE);
|
||||
auto nNoError = GetPrivateProfileIntW(L"patches", L"no_error", FALSE, CONFIG_FILE);
|
||||
auto nESM = GetPrivateProfileIntW(L"patches", L"enhanced_stage_manager", FALSE, CONFIG_FILE);
|
||||
auto nESMF = GetPrivateProfileIntW(L"patches", L"enhanced_stage_manager_final", 2, CONFIG_FILE);
|
||||
auto nESME = GetPrivateProfileIntW(L"patches", L"enhanced_stage_manager_encore", 3, CONFIG_FILE);
|
||||
auto nESMHE = GetPrivateProfileIntW(L"patches", L"enhanced_stage_manager_has_encore", FALSE, CONFIG_FILE);
|
||||
|
||||
// Hides the Freeplay text
|
||||
if (nHideFreeplay)
|
||||
{
|
||||
InjectCode((void*)0x00000001403BABEF, { 0x06, 0xB6 });
|
||||
printf("[Patches] Hide Freeplay enabled\n");
|
||||
}
|
||||
// Use GLUT_CURSOR_RIGHT_ARROW instead of GLUT_CURSOR_NONE
|
||||
if (nCursor)
|
||||
{
|
||||
InjectCode((void*)0x000000014019341B, { 0x00 });
|
||||
printf("[Patches] Cursor enabled\n");
|
||||
}
|
||||
// Override status icon states to be invalid (hides them)
|
||||
if (nStatusIcons > 0)
|
||||
{
|
||||
std::vector<uint8_t> cardIcon = { 0xFD, 0x0A };
|
||||
std::vector<uint8_t> networkIcon = { 0x9E, 0x1E };
|
||||
|
||||
if (nStatusIcons == 2) // 2 for error icons
|
||||
{
|
||||
cardIcon = { 0xFA, 0x0A };
|
||||
networkIcon = { 0x9F, 0x1E };
|
||||
printf("[Patches] Status icons set to error state\n");
|
||||
}
|
||||
else if (nStatusIcons == 3) // 3 for OK icons
|
||||
{
|
||||
cardIcon = { 0xFC, 0x0A };
|
||||
networkIcon = { 0xA0, 0x1E };
|
||||
printf("[Patches] Status icons set to OK state\n");
|
||||
}
|
||||
else if (nStatusIcons == 4) // 4 for partial OK icons
|
||||
{
|
||||
cardIcon = { 0xFB, 0x0A };
|
||||
networkIcon = { 0xA1, 0x1E };
|
||||
printf("[Patches] Status icons set to partial OK state\n");
|
||||
}
|
||||
else // 1 or invalid for hidden
|
||||
{
|
||||
cardIcon = { 0xFD, 0x0A };
|
||||
networkIcon = { 0x9E, 0x1E };
|
||||
printf("[Patches] Status icons hidden\n");
|
||||
}
|
||||
|
||||
// card icon
|
||||
InjectCode((void*)0x00000001403B9D6E, cardIcon); // error state
|
||||
InjectCode((void*)0x00000001403B9D73, cardIcon); // OK state
|
||||
|
||||
// network icon
|
||||
InjectCode((void*)0x00000001403BA14B, networkIcon); // error state
|
||||
InjectCode((void*)0x00000001403BA155, networkIcon); // OK state
|
||||
InjectCode((void*)0x00000001403BA16B, networkIcon); // partial state
|
||||
|
||||
InjectCode((void*)0x00000001403BA1A5, { 0x48, 0xE9 }); // never show the error code for partial connection
|
||||
|
||||
// I was going to use this with a string, but the assignment wasn't behaving well and making separate prints was easier than figuring it out
|
||||
// printf("[Patches] Status icons %s\n", iconType);
|
||||
}
|
||||
// Removes PV watermark
|
||||
if (nHidePVWatermark)
|
||||
{
|
||||
InjectCode((void*)0x0000000140A13A88, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 });
|
||||
printf("[Patches] PV watermark hidden\n");
|
||||
}
|
||||
// Disable the PV screen photo UI
|
||||
if (nNoPVUi)
|
||||
{
|
||||
InjectCode((void*)0x000000014048FA91, { 0xEB, 0x6F }); // skip button panel image (JMP 0x14048FB02)
|
||||
|
||||
// patch minimum PV UI state to 1 instead of 0
|
||||
// hook check for lyrics enabled (UI state < 2) to change UI state 0 into 1
|
||||
// dump new code in the skipped button panel condition
|
||||
InjectCode((void*)0x000000014048FA93, { 0xC7, 0x83, 0x58, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 }); // MOV dword ptr [0x158 + RBX],0x1
|
||||
InjectCode((void*)0x000000014048FA9D, { 0xC6, 0x80, 0x3A, 0xD1, 0x02, 0x00, 0x01 }); // MOV byte ptr [0x2d13a + RAX],0x1
|
||||
InjectCode((void*)0x000000014048FAA4, { 0xE9, 0x8B, 0xFB, 0xFF, 0xFF }); // JMP 0x14048F634
|
||||
|
||||
InjectCode((void*)0x000000014048F62D, { 0xE9, 0x61, 0x04, 0x00, 0x00 }); // JMP 0x14048FA93
|
||||
|
||||
printf("[Patches] PV UI disabled\n");
|
||||
}
|
||||
// Don't show volume control
|
||||
if (nHideVolCtrl)
|
||||
{
|
||||
// skip SE button
|
||||
InjectCode((void*)0x00000001409A4D60, { 0xC0, 0xD3 });
|
||||
|
||||
// skip volume sliders button
|
||||
InjectCode((void*)0x0000000140A85F10, { 0xE0, 0x50 });
|
||||
|
||||
printf("[Patches] Volume control hidden\n");
|
||||
}
|
||||
// Skip loading (and therefore displaying) song lyrics
|
||||
if (nNoLyrics)
|
||||
{
|
||||
InjectCode((void*)0x00000001404E7A25, { 0x00, 0x00 });
|
||||
InjectCode((void*)0x00000001404E7950, { 0x48, 0xE9 }); // ensure first iteration doesn't run
|
||||
printf("[Patches] Lyrics disabled\n");
|
||||
}
|
||||
// Skip loading (and therefore displaying) song movies
|
||||
if (nNoMovies)
|
||||
{
|
||||
InjectCode((void*)0x00000001404EB584, { 0x48, 0xE9 });
|
||||
InjectCode((void*)0x00000001404EB471, { 0x48, 0xE9 });
|
||||
printf("[Patches] Movies disabled\n");
|
||||
}
|
||||
// Disable error banner
|
||||
if (nNoError)
|
||||
{
|
||||
// Disable Errors Banner
|
||||
InjectCode((void*)0x00000001403B9E9B, { 0x90, 0x90 });
|
||||
printf("[Patches] Errors Banner disabled\n");
|
||||
}
|
||||
// Enhanced Stage Manager
|
||||
if (nESM)
|
||||
{
|
||||
// Replace the function that provides the number of stages and compact some of it
|
||||
InjectCode((void*)0x000000014038AEF0, { 0x48, 0x8B, 0x88, 0x40, 0x01, 0x00, 0x00, 0x48, 0x89, 0x4C, 0x24, 0x20, 0x48, 0x8B, 0xD0, 0x48, 0x8B, 0x88, 0x48, 0x01, 0x00, 0x00, 0x48, 0x89, 0x4C, 0x24, 0x28, 0x8B, 0x88, 0x50, 0x01, 0x00, 0x00, 0x89, 0x4C, 0x24, 0x30, 0x8B, 0x88, 0x54, 0x01, 0x00, 0x00, 0x8B, 0x80, 0x58, 0x01, 0x00, 0x00, 0x89, 0x44, 0x24, 0x38, 0x8B, 0x82, 0x5C, 0x01, 0x00, 0x00, 0x89, 0x4C, 0x24, 0x34, 0x89, 0x44, 0x24, 0x3C, 0x48, 0x8B, 0x82, 0x60, 0x01, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x40, 0x48, 0x8B, 0x82, 0x68, 0x01, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x48, 0x48, 0x8B, 0x82, 0x70, 0x01, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x50, 0x8B, 0x82, 0x78, 0x01, 0x00, 0x00, 0x89, 0x44, 0x24, 0x58, 0x84, 0xC0, 0x74, 0x2A, 0x48, 0x8B, 0x44, 0x24, 0x38, 0x48, 0xC1, 0xE8, 0x20, 0x85, 0xC0, 0x75, 0x1D, 0xE8, 0xD9, 0xD9, 0xE5, 0xFF, 0x48, 0x85, 0xC0, 0x74, 0x13, 0x48, 0x8D, 0x48, 0x10, 0xE8, 0xFB, 0xD3, 0xE5, 0xFF, 0xB9, 0x03, 0x00, 0x00, 0x00, 0x85, 0xC0, 0x0F, 0x45, 0xD9, 0x8B, 0x1D, 0x1B, 0x0C, 0x00, 0x00, 0x83, 0x3D, 0x1C, 0x0C, 0x00, 0x00, 0x00, 0x74, 0x06, 0x8B, 0x1D, 0x10, 0x0C, 0x00, 0x00, 0x8B, 0xC3, 0x48, 0x83, 0xC4, 0x60, 0x5B, 0xC3, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC });
|
||||
|
||||
// Jump to another section by addding some code to replace the values (Jump 1)
|
||||
InjectCode((void*)0x000000014038AFF4, { 0xE9, 0x87, 0x0B, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC });
|
||||
|
||||
// Jump to another section by addding some code to replace the values (Replace 1/2) while some reserving space for values
|
||||
InjectCode((void*)0x000000014038BB40, { 0xFF, 0x05, 0x76, 0x00, 0x00, 0x00, 0x8B, 0x0D, 0x70, 0x00, 0x00, 0x00, 0xBA, 0x02, 0x00, 0x00, 0x00, 0x83, 0x3D, 0x60, 0x00, 0x00, 0x00, 0x00, 0x74, 0x02, 0xFF, 0xC2, 0x39, 0xD1, 0x0F, 0x4D, 0xCA, 0x89, 0x48, 0x08, 0xB9, 0x0E, 0x00, 0x00, 0x00, 0xE8, 0x92, 0x98, 0xE0, 0xFF, 0xB0, 0x01, 0x48, 0x83, 0xC4, 0x28, 0xC3, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x44, 0x89, 0x61, 0x08, 0x44, 0x88, 0x61, 0x0C, 0x4C, 0x89, 0x61, 0x10, 0x44, 0x89, 0x25, 0x29, 0x00, 0x00, 0x00, 0xE9, 0x68, 0xF4, 0xFF, 0xFF, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
|
||||
|
||||
// Use the value from our own address instead of the original one
|
||||
InjectCode((void*)0x00000001403F65AF, { 0x48, 0x8D, 0x05, 0x4A, 0x18, 0xDA, 0x00, 0x8B, 0x1D, 0x00, 0x56 });
|
||||
|
||||
// Jump to another section by addding some code to replace the values (Jump 2)
|
||||
InjectCode((void*)0x00000001403F6638, { 0xE9, 0x03, 0x55, 0xF9, 0xFF, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC});
|
||||
|
||||
DWORD StageCountProtect;
|
||||
VirtualProtect((int32_t*)0x14038BBB0, 0x10, PAGE_EXECUTE_READWRITE, &StageCountProtect);
|
||||
|
||||
int* ESM = (int*)0x000000014038BBB0;
|
||||
|
||||
ESM[0] = nESMF;
|
||||
ESM[1] = nESME;
|
||||
ESM[2] = nESMHE;
|
||||
|
||||
printf("[Patches] Enhanced Stage Manager enabled\n");
|
||||
}
|
||||
}
|
||||
|
||||
void InjectCode(void* address, const std::vector<uint8_t> data)
|
||||
{
|
||||
const size_t byteCount = data.size() * sizeof(uint8_t);
|
||||
|
||||
DWORD oldProtect;
|
||||
VirtualProtect(address, byteCount, PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
memcpy(address, data.data(), byteCount);
|
||||
VirtualProtect(address, byteCount, oldProtect, nullptr);
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<ProjectGuid>{89F87459-768F-4638-9267-0F90CD74452D}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>Render</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<TargetExt>.dva</TargetExt>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<TargetExt>.dva</TargetExt>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;RENDER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>
|
||||
</PrecompiledHeaderFile>
|
||||
<AdditionalIncludeDirectories>..\..\..\dependencies\freeglut\include;..\..\..\dependencies\detours\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<AdditionalLibraryDirectories>..\..\..\dependencies\detours\lib;..\..\..\dependencies\freeglut\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;RENDER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;RENDER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>
|
||||
</PrecompiledHeaderFile>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>..\..\..\dependencies\freeglut\include;..\..\..\dependencies\detours\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<AdditionalLibraryDirectories>..\..\..\dependencies\detours\lib;..\..\..\dependencies\freeglut\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;RENDER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="framework.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="framework.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,98 @@
|
||||
#include "framework.h"
|
||||
#include <detours.h>
|
||||
#pragma comment(lib, "detours.lib")
|
||||
#include <GL\freeglut.h>
|
||||
#include <GL\GL.h>
|
||||
#include <wingdi.h>
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
|
||||
int hookedCreateWindow(const char* title, void(__cdecl* exit_function)(int))
|
||||
{
|
||||
if (nDisplay == 1) // borderless fullscreen
|
||||
{
|
||||
*fullScreenFlag = 0;
|
||||
int nWidth = glutGet(GLUT_SCREEN_WIDTH);
|
||||
int nHeight = glutGet(GLUT_SCREEN_HEIGHT);
|
||||
int nX = 0;
|
||||
int nY = 0;
|
||||
|
||||
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH | GLUT_BORDERLESS);
|
||||
glutInitWindowSize(nWidth, nHeight);
|
||||
glutInitWindowPosition(nX, nY);
|
||||
glutCreateWindow(title);
|
||||
|
||||
if (glutGet(GLUT_WINDOW_X) != nX || glutGet(GLUT_WINDOW_Y) != nY) // if not in borderless mode (top left of client area isn't top left of window position)
|
||||
{
|
||||
// support borderless mode even with original copy of glut
|
||||
HDC hDev = wglGetCurrentDC(); // get handle to current opengl device context
|
||||
HWND hWnd = WindowFromDC(hDev); // convert it to a window handle
|
||||
SetWindowLongPtr(hWnd, GWL_STYLE, WS_POPUP); // set popup style (no border)
|
||||
SetWindowPos(hWnd, HWND_TOP, 0, 0, nWidth, nHeight, 0); // adjust position to apply new style
|
||||
}
|
||||
|
||||
printf("[Render Manager] Borderless mode.\n");
|
||||
}
|
||||
else if (nDisplay == 2) // fullscreen
|
||||
{
|
||||
char GameModeString[24];
|
||||
sprintf_s(GameModeString, sizeof(GameModeString), "%dx%d:%d@%d", nWidth, nHeight, nBitDepth, nRefreshRate);
|
||||
glutGameModeString(GameModeString);
|
||||
|
||||
if (glutGameModeGet(GLUT_GAME_MODE_POSSIBLE)) {
|
||||
printf("[Render Manager] Game mode (exclusive fullscreen) enabled.\n");
|
||||
printf(GameModeString);
|
||||
printf("\n");
|
||||
glutEnterGameMode();
|
||||
}
|
||||
else {
|
||||
printf("[Render Manager] Requested display mode not supported. Using non-exclusive fullscreen instead.\n");
|
||||
printf(GameModeString);
|
||||
printf("\n");
|
||||
*fullScreenFlag = 1;
|
||||
glutCreateWindow(title);
|
||||
}
|
||||
}
|
||||
else // windowed
|
||||
{
|
||||
*fullScreenFlag = 0;
|
||||
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
|
||||
glutInitWindowSize(nWidth, nHeight);
|
||||
glutInitWindowPosition((glutGet(GLUT_SCREEN_WIDTH) - nWidth) / 2, (glutGet(GLUT_SCREEN_HEIGHT) - nHeight) / 2); // Center to the middle of the screen when windowed
|
||||
glutCreateWindow(title);
|
||||
printf("[Render Manager] Windowed mode.\n");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
__int64 hookedParseParameters(int a1, __int64* a2)
|
||||
{
|
||||
// Force -wqhd if Custom Internal Resolution is enabled
|
||||
if (nIntRes)
|
||||
*resolutionType = 15;
|
||||
// Return to the original function
|
||||
return divaParseParameters(a1, a2);
|
||||
}
|
||||
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule,
|
||||
DWORD ul_reason_for_call,
|
||||
LPVOID lpReserved
|
||||
)
|
||||
{
|
||||
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
|
||||
{
|
||||
DisableThreadLibraryCalls(hModule);
|
||||
DetourTransactionBegin();
|
||||
DetourUpdateThread(GetCurrentThread());
|
||||
DetourAttach(&(PVOID&)divaCreateWindow, hookedCreateWindow);
|
||||
DetourTransactionCommit();
|
||||
|
||||
DetourTransactionBegin();
|
||||
DetourUpdateThread(GetCurrentThread());
|
||||
DetourAttach(&(PVOID&)divaParseParameters, hookedParseParameters);
|
||||
DetourTransactionCommit();
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
// Windows Header Files
|
||||
#include <windows.h>
|
||||
#include <string>
|
||||
|
||||
static int(__cdecl* divaCreateWindow)(const char* title, void(__cdecl* exitfunc)(int)) = (int(__cdecl*)(const char* title, void(__cdecl * exitfunc)(int)))0x140194D00;
|
||||
__int64 (__fastcall* divaParseParameters)(int a1, __int64* a2) = (__int64(__fastcall*)(int a1, __int64* a2))0x140193630;
|
||||
|
||||
uint8_t* fullScreenFlag = (uint8_t*)0x140EDA5D1;
|
||||
DWORD* resolutionType = (DWORD*)0x140EDA5D4;
|
||||
|
||||
using namespace std;
|
||||
|
||||
wstring DirPath() {
|
||||
WCHAR buffer[MAX_PATH];
|
||||
GetModuleFileNameW(NULL, buffer, MAX_PATH);
|
||||
wstring::size_type pos = wstring(buffer).find_last_of(L"\\/");
|
||||
return wstring(buffer).substr(0, pos);
|
||||
}
|
||||
|
||||
wstring CONFIG_FILE_STRING = DirPath() + L"\\plugins\\config.ini";
|
||||
LPCWSTR CONFIG_FILE = CONFIG_FILE_STRING.c_str();
|
||||
|
||||
int nDisplay = GetPrivateProfileIntW(L"resolution", L"display", 0, CONFIG_FILE);
|
||||
int nWidth = GetPrivateProfileIntW(L"resolution", L"width", 1280, CONFIG_FILE);
|
||||
int nHeight = GetPrivateProfileIntW(L"resolution", L"height", 720, CONFIG_FILE);
|
||||
|
||||
int nIntRes = GetPrivateProfileIntW(L"resolution", L"r.enable", FALSE, CONFIG_FILE);
|
||||
int nIntResWidth = GetPrivateProfileIntW(L"resolution", L"r.width", 1280, CONFIG_FILE);
|
||||
int nIntResHeight = GetPrivateProfileIntW(L"resolution", L"r.height", 720, CONFIG_FILE);
|
||||
|
||||
int nBitDepth = GetPrivateProfileIntW(L"resolution", L"bitdepth", 32, CONFIG_FILE);
|
||||
int nRefreshRate = GetPrivateProfileIntW(L"resolution", L"refreshrate", 60, CONFIG_FILE);
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
#include "CameraController.h"
|
||||
#include <algorithm>
|
||||
#include "Input/InputState.h"
|
||||
#include "ComponentsManager.h"
|
||||
#include "../framework.h"
|
||||
#include "../Input/Mouse/Mouse.h"
|
||||
#include "../Input/Keyboard/Keyboard.h"
|
||||
#include "../Input/Bindings/KeyboardBinding.h"
|
||||
|
||||
#define GLUT_CURSOR_RIGHT_ARROW 0x0000
|
||||
#define GLUT_CURSOR_NONE 0x0065
|
||||
|
||||
using namespace TLAC::Input;
|
||||
using namespace TLAC::Utilities;
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
CameraController::CameraController()
|
||||
{
|
||||
}
|
||||
|
||||
CameraController::~CameraController()
|
||||
{
|
||||
delete ToggleBinding;
|
||||
|
||||
delete ForwardBinding;
|
||||
delete BackwardBinding;
|
||||
delete LeftBinding;
|
||||
delete RightBinding;
|
||||
|
||||
delete UpBinding;
|
||||
delete DownBinding;
|
||||
delete ClockwiseBinding;
|
||||
delete CounterClockwiseBinding;
|
||||
delete ZoomInBinding;
|
||||
delete ZoomOutBinding;
|
||||
|
||||
delete FastBinding;
|
||||
delete SlowBinding;
|
||||
}
|
||||
|
||||
const char* CameraController::GetDisplayName()
|
||||
{
|
||||
return "camera_controller";
|
||||
}
|
||||
|
||||
void CameraController::Initialize(ComponentsManager* manager)
|
||||
{
|
||||
componentsManager = manager;
|
||||
|
||||
printf("[TLAC] CameraController::Initialize(): Initialized\n");
|
||||
|
||||
for (int i = 0; i < sizeof(cameraSetterAddresses) / sizeof(void*); i++)
|
||||
{
|
||||
DWORD oldProtect;
|
||||
VirtualProtect((void*)cameraSetterAddresses[i], sizeof(uint8_t), PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
|
||||
originalSetterBytes[i] = *(uint8_t*)cameraSetterAddresses[i];
|
||||
}
|
||||
|
||||
ToggleBinding = new Binding();
|
||||
ToggleBinding->AddBinding(new KeyboardBinding(VK_F3));
|
||||
|
||||
ForwardBinding = new Binding();
|
||||
ForwardBinding->AddBinding(new KeyboardBinding('W'));
|
||||
BackwardBinding = new Binding();
|
||||
BackwardBinding->AddBinding(new KeyboardBinding('S'));
|
||||
LeftBinding = new Binding();
|
||||
LeftBinding->AddBinding(new KeyboardBinding('A'));
|
||||
RightBinding = new Binding();
|
||||
RightBinding->AddBinding(new KeyboardBinding('D'));
|
||||
|
||||
UpBinding = new Binding();
|
||||
UpBinding->AddBinding(new KeyboardBinding(VK_SPACE));
|
||||
DownBinding = new Binding();
|
||||
DownBinding->AddBinding(new KeyboardBinding(VK_CONTROL));
|
||||
|
||||
ClockwiseBinding = new Binding();
|
||||
ClockwiseBinding->AddBinding(new KeyboardBinding('E'));
|
||||
CounterClockwiseBinding = new Binding();
|
||||
CounterClockwiseBinding->AddBinding(new KeyboardBinding('Q'));
|
||||
|
||||
ZoomInBinding = new Binding();
|
||||
ZoomInBinding->AddBinding(new KeyboardBinding('R'));
|
||||
ZoomOutBinding = new Binding();
|
||||
ZoomOutBinding->AddBinding(new KeyboardBinding('F'));
|
||||
|
||||
FastBinding = new Binding();
|
||||
FastBinding->AddBinding(new KeyboardBinding(VK_SHIFT));
|
||||
SlowBinding = new Binding();
|
||||
SlowBinding->AddBinding(new KeyboardBinding(VK_MENU));
|
||||
|
||||
camera = (Camera*)CAMERA_ADDRESS;
|
||||
}
|
||||
|
||||
void CameraController::Update()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void CameraController::UpdateInput()
|
||||
{
|
||||
if (ToggleBinding->AnyTapped())
|
||||
{
|
||||
SetControls(!GetIsEnabled());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GetIsEnabled())
|
||||
return;
|
||||
|
||||
auto keyboard = Keyboard::GetInstance();
|
||||
auto mouse = Mouse::GetInstance();
|
||||
|
||||
bool forward = ForwardBinding->AnyDown();
|
||||
bool backward = BackwardBinding->AnyDown();
|
||||
bool left = LeftBinding->AnyDown();
|
||||
bool right = RightBinding->AnyDown();
|
||||
|
||||
bool up = UpBinding->AnyDown();
|
||||
bool down = DownBinding->AnyDown();
|
||||
|
||||
bool fast = FastBinding->AnyDown();
|
||||
bool slow = SlowBinding->AnyDown();
|
||||
|
||||
bool clockwise = ClockwiseBinding->AnyDown();
|
||||
bool counterclockwise = CounterClockwiseBinding->AnyDown();
|
||||
|
||||
bool zoomin = ZoomInBinding->AnyDown();
|
||||
bool zoomout = ZoomOutBinding->AnyDown();
|
||||
|
||||
float speed = GetElapsedTime() * (fast ? fastSpeed : slow ? slowSpeed : normalSpeed);
|
||||
|
||||
if (forward ^ backward)
|
||||
camera->Position += PointFromAngle(verticalRotation + (forward ? +0.0f : -180.0f), speed);
|
||||
|
||||
if (left ^ right)
|
||||
camera->Position += PointFromAngle(verticalRotation + (right ? +90.0f : -90.0f), speed);
|
||||
|
||||
if (up ^ down)
|
||||
camera->Position.Y += speed * (up ? +0.25f : -0.25f);
|
||||
|
||||
if (clockwise ^ counterclockwise)
|
||||
camera->Rotation += speed * (clockwise ? -1.0f : +1.0f);
|
||||
|
||||
if (zoomin ^ zoomout)
|
||||
{
|
||||
camera->HorizontalFov += speed * (zoomin ? -1.0f : +1.0f);
|
||||
camera->HorizontalFov = std::clamp(camera->HorizontalFov, +1.0f, +170.0f);
|
||||
}
|
||||
|
||||
if (mouse->HasMoved())
|
||||
{
|
||||
SetMouseWindowCenter();
|
||||
|
||||
auto delta = mouse->GetDeltaPosition();
|
||||
|
||||
verticalRotation += delta.x * sensitivity;
|
||||
horizontalRotation -= delta.y * (sensitivity / 5.0f);
|
||||
|
||||
horizontalRotation = std::clamp(horizontalRotation, -75.0f, +75.0f);
|
||||
}
|
||||
|
||||
((InputState*)*(uint64_t*)INPUT_STATE_PTR_ADDRESS)->HideCursor();
|
||||
|
||||
Vec2 focus = PointFromAngle(verticalRotation, 1.0f);
|
||||
camera->Focus.X = camera->Position.X + focus.X;
|
||||
camera->Focus.Z = camera->Position.Z + focus.Y;
|
||||
|
||||
camera->Focus.Y = camera->Position.Y + PointFromAngle(horizontalRotation, 5.0f).X;
|
||||
}
|
||||
|
||||
void CameraController::SetControls(bool value)
|
||||
{
|
||||
if (GetIsEnabled() == value)
|
||||
return;
|
||||
|
||||
SetIsEnabled(value);
|
||||
componentsManager->SetUpdateGameInput(!value);
|
||||
|
||||
printf("[TLAC] CameraController::SetControls(): enabled = %s\n", GetIsEnabled() ? "true" : "false");
|
||||
|
||||
typedef void __stdcall _glutSetCursor(int);
|
||||
auto glutSetCursor = (_glutSetCursor*)GLUT_SET_CURSOR_ADDRESS;
|
||||
|
||||
// hide cursor
|
||||
glutSetCursor(value ? GLUT_CURSOR_NONE : GLUT_CURSOR_RIGHT_ARROW);
|
||||
|
||||
if (value)
|
||||
{
|
||||
// disable camera setters
|
||||
for (int i = 0; i < sizeof(cameraSetterAddresses) / sizeof(void*); i++)
|
||||
*(uint8_t*)cameraSetterAddresses[i] = RET_OPCODE;
|
||||
|
||||
// set initial camera angle
|
||||
Vec2 camXz = Vec2(camera->Position.X, camera->Position.Z);
|
||||
Vec2 focusXz = Vec2(camera->Focus.X, camera->Focus.Z);
|
||||
verticalRotation = AngleFromPoints(camXz, focusXz);
|
||||
|
||||
horizontalRotation = 0;
|
||||
camera->Rotation = defaultRotation;
|
||||
camera->HorizontalFov = defaultFov;
|
||||
}
|
||||
else
|
||||
{
|
||||
// restore camera setters
|
||||
for (int i = 0; i < sizeof(cameraSetterAddresses) / sizeof(void*); i++)
|
||||
*(uint8_t*)cameraSetterAddresses[i] = originalSetterBytes[i];
|
||||
}
|
||||
}
|
||||
|
||||
void CameraController::SetMouseWindowCenter()
|
||||
{
|
||||
RECT windowRect = framework::GetWindowBounds();
|
||||
|
||||
int centerX = windowRect.left + (windowRect.right - windowRect.left) / 2;
|
||||
int centerY = windowRect.top + (windowRect.bottom - windowRect.top) / 2;
|
||||
|
||||
Mouse::GetInstance()->SetPosition(centerX, centerY);
|
||||
}
|
||||
|
||||
bool CameraController::GetIsEnabled()
|
||||
{
|
||||
return isEnabled;
|
||||
}
|
||||
|
||||
void CameraController::SetIsEnabled(bool value)
|
||||
{
|
||||
isEnabled = value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
#pragma once
|
||||
#include "EmulatorComponent.h"
|
||||
#include "../Constants.h"
|
||||
#include "../Input/Bindings/Binding.h"
|
||||
#include "../Utilities/Math.h"
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
struct Camera
|
||||
{
|
||||
Utilities::Vec3 Position;
|
||||
Utilities::Vec3 Focus;
|
||||
float Rotation;
|
||||
float HorizontalFov;
|
||||
float VerticalFov;
|
||||
};
|
||||
|
||||
class CameraController : public EmulatorComponent
|
||||
{
|
||||
public:
|
||||
Input::Binding* ToggleBinding;
|
||||
|
||||
Input::Binding* ForwardBinding;
|
||||
Input::Binding* BackwardBinding;
|
||||
Input::Binding* LeftBinding;
|
||||
Input::Binding* RightBinding;
|
||||
|
||||
Input::Binding* UpBinding;
|
||||
Input::Binding* DownBinding;
|
||||
Input::Binding* FastBinding;
|
||||
Input::Binding* SlowBinding;
|
||||
|
||||
Input::Binding* ClockwiseBinding;
|
||||
Input::Binding* CounterClockwiseBinding;
|
||||
|
||||
Input::Binding* ZoomInBinding;
|
||||
Input::Binding* ZoomOutBinding;
|
||||
|
||||
CameraController();
|
||||
~CameraController();
|
||||
|
||||
virtual const char* GetDisplayName() override;
|
||||
|
||||
virtual void Initialize(ComponentsManager*) override;
|
||||
virtual void Update() override;
|
||||
virtual void UpdateInput() override;
|
||||
|
||||
void SetControls(bool value);
|
||||
|
||||
bool GetIsEnabled();
|
||||
|
||||
private:
|
||||
const float fastSpeed = 0.1f;
|
||||
const float slowSpeed = 0.0005f;
|
||||
const float normalSpeed = 0.005f;
|
||||
|
||||
const float defaultRotation = 0.0f;
|
||||
const float defaultFov = 70.0f;
|
||||
const float sensitivity = 0.25f;
|
||||
|
||||
ComponentsManager* componentsManager;
|
||||
float verticalRotation;
|
||||
float horizontalRotation;
|
||||
|
||||
bool isEnabled;
|
||||
Camera* camera;
|
||||
|
||||
uint8_t originalSetterBytes[4];
|
||||
void* cameraSetterAddresses[4] =
|
||||
{
|
||||
(void*)CAMERA_POS_SETTER_ADDRESS,
|
||||
(void*)CAMERA_INTR_SETTER_ADDRESS,
|
||||
(void*)CAMERA_ROT_SETTER_ADDRESS,
|
||||
(void*)CAMERA_PERS_SETTER_ADDRESS,
|
||||
};
|
||||
|
||||
void SetMouseWindowCenter();
|
||||
void SetIsEnabled(bool value);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
#include "ComponentsManager.h"
|
||||
#include "../FileSystem/ConfigFile.h"
|
||||
#include "../framework.h"
|
||||
#include "Input/InputEmulator.h"
|
||||
#include "Input/TouchSliderEmulator.h"
|
||||
#include "Input/TouchPanelEmulator.h"
|
||||
#include "SysTimer.h"
|
||||
#include "PlayerDataManager.h"
|
||||
#include "FrameRateManager.h"
|
||||
#include "FastLoader.h"
|
||||
#include "StageManager.h"
|
||||
#include "CameraController.h"
|
||||
#include "DebugComponent.h"
|
||||
#include "ScaleComponent.h"
|
||||
#include "FPSLimiter.h"
|
||||
#include "GameTargets/TargetInspector.h"
|
||||
|
||||
using ConfigFile = TLAC::FileSystem::ConfigFile;
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
typedef void EngineUpdateInput(void*);
|
||||
|
||||
ComponentsManager::ComponentsManager()
|
||||
{
|
||||
}
|
||||
|
||||
ComponentsManager::~ComponentsManager()
|
||||
{
|
||||
}
|
||||
|
||||
void ComponentsManager::ParseAddComponents()
|
||||
{
|
||||
EmulatorComponent* allComponents[]
|
||||
{
|
||||
new TargetInspector(),
|
||||
new InputEmulator(),
|
||||
new TouchSliderEmulator(),
|
||||
new TouchPanelEmulator(),
|
||||
new SysTimer(),
|
||||
new PlayerDataManager(),
|
||||
new FrameRateManager(),
|
||||
new FastLoader(),
|
||||
new ScaleComponent(),
|
||||
new FPSLimiter(),
|
||||
new StageManager(),
|
||||
new CameraController(),
|
||||
new DebugComponent(),
|
||||
};
|
||||
|
||||
ConfigFile componentsConfig(framework::GetModuleDirectory(), COMPONENTS_CONFIG_FILE_NAME);
|
||||
bool success = componentsConfig.OpenRead();
|
||||
|
||||
if (!success)
|
||||
{
|
||||
printf("ComponentsManager::ParseAddComponents(): Unable to parse %s\n", COMPONENTS_CONFIG_FILE_NAME.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
size_t componentCount = sizeof(allComponents) / sizeof(EmulatorComponent*);
|
||||
components.reserve(componentCount);
|
||||
|
||||
std::string trueString = "true", falseString = "false";
|
||||
|
||||
for (int i = 0; i < componentCount; i++)
|
||||
{
|
||||
std::string* value;
|
||||
|
||||
auto name = allComponents[i]->GetDisplayName();
|
||||
//printf("ComponentsManager::ParseAddComponents(): searching name: %s\n", name);
|
||||
|
||||
if (componentsConfig.TryGetValue(name, &value))
|
||||
{
|
||||
//printf("ComponentsManager::ParseAddComponents(): %s found\n", name);
|
||||
|
||||
if (*value == trueString)
|
||||
{
|
||||
//printf("ComponentsManager::ParseAddComponents(): enabling %s...\n", name);
|
||||
components.push_back(allComponents[i]);
|
||||
}
|
||||
else if (*value == falseString)
|
||||
{
|
||||
//printf("ComponentsManager::ParseAddComponents(): disabling %s...\n", name);
|
||||
}
|
||||
else
|
||||
{
|
||||
//printf("ComponentsManager::ParseAddComponents(): invalid value %s for component %s\n", value, name);
|
||||
}
|
||||
|
||||
delete value;
|
||||
}
|
||||
else
|
||||
{
|
||||
//printf("ParseAddComponents(): component %s not found\n", name);
|
||||
delete allComponents[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ComponentsManager::Initialize()
|
||||
{
|
||||
dwGuiDisplay = (DwGuiDisplay*) * (uint64_t*)DW_GUI_DISPLAY_INSTANCE_PTR_ADDRESS;
|
||||
|
||||
ParseAddComponents();
|
||||
updateStopwatch.Start();
|
||||
|
||||
for (auto& component : components)
|
||||
component->Initialize(this);
|
||||
}
|
||||
|
||||
void ComponentsManager::Update()
|
||||
{
|
||||
elpasedTime = updateStopwatch.Restart();
|
||||
|
||||
for (auto& component : components)
|
||||
{
|
||||
component->SetElapsedTime(elpasedTime);
|
||||
component->Update();
|
||||
}
|
||||
}
|
||||
|
||||
void ComponentsManager::UpdateInput()
|
||||
{
|
||||
if (!GetIsInputEmulatorUsed())
|
||||
{
|
||||
uint64_t* inputStatePtr = (uint64_t*)INPUT_STATE_PTR_ADDRESS;
|
||||
|
||||
// poll input using the original PollInput function we overwrote with the update hook instead
|
||||
if (inputStatePtr != nullptr)
|
||||
((EngineUpdateInput*)ENGINE_UPDATE_INPUT_ADDRESS)((void*)* inputStatePtr);
|
||||
}
|
||||
|
||||
for (auto& component : components)
|
||||
component->UpdateInput();
|
||||
}
|
||||
|
||||
void ComponentsManager::OnFocusGain()
|
||||
{
|
||||
for (auto& component : components)
|
||||
component->OnFocusGain();
|
||||
}
|
||||
|
||||
void ComponentsManager::OnFocusLost()
|
||||
{
|
||||
for (auto& component : components)
|
||||
component->OnFocusLost();
|
||||
}
|
||||
|
||||
void ComponentsManager::Dispose()
|
||||
{
|
||||
for (auto& component : components)
|
||||
delete component;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
#include "EmulatorComponent.h"
|
||||
#include "../Utilities/Stopwatch.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
const std::string COMPONENTS_CONFIG_FILE_NAME = "components.ini";
|
||||
|
||||
// Incomplete type
|
||||
struct DwGuiDisplay
|
||||
{
|
||||
void* vftable;
|
||||
void* active;
|
||||
void* cap;
|
||||
void* on;
|
||||
void* move;
|
||||
void* widget;
|
||||
};
|
||||
|
||||
class ComponentsManager
|
||||
{
|
||||
public:
|
||||
ComponentsManager();
|
||||
~ComponentsManager();
|
||||
void Initialize();
|
||||
void Update();
|
||||
void UpdateInput();
|
||||
void OnFocusGain();
|
||||
void OnFocusLost();
|
||||
void Dispose();
|
||||
|
||||
inline bool GetIsInputEmulatorUsed() { return isInputEmulatorUsed; };
|
||||
inline void SetIsInputEmulatorUsed(bool value) { isInputEmulatorUsed = value; };
|
||||
|
||||
inline bool GetUpdateGameInput() { return updateGameInput; };
|
||||
inline void SetUpdateGameInput(bool value) { updateGameInput = value; }
|
||||
|
||||
inline bool IsDwGuiActive() { return dwGuiDisplay->active != nullptr; };
|
||||
inline bool IsDwGuiHovered() { return dwGuiDisplay->on != nullptr; };
|
||||
|
||||
private:
|
||||
DwGuiDisplay* dwGuiDisplay;
|
||||
|
||||
bool isInputEmulatorUsed = false;
|
||||
bool updateGameInput = true;
|
||||
|
||||
float elpasedTime;
|
||||
Utilities::Stopwatch updateStopwatch;
|
||||
std::vector<EmulatorComponent*> components;
|
||||
|
||||
void ParseAddComponents();
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
struct CustomPlayerData
|
||||
{
|
||||
std::string *PlayerName;
|
||||
std::string* LevelName;
|
||||
int LevelPlateId;
|
||||
int SkinEquip;
|
||||
int BtnSeEquip;
|
||||
int SlideSeEquip;
|
||||
int ChainslideSeEquip;
|
||||
bool ShowGreatClearBorder;
|
||||
bool ShowExcellentClearBorder;
|
||||
bool UseCard;
|
||||
bool GameModifierOptions;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
#include "DebugComponent.h"
|
||||
#include "../Constants.h"
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
const char* GameStateNames[] =
|
||||
{
|
||||
"STARTUP",
|
||||
"ADVERTISE",
|
||||
"GAME",
|
||||
"DATA_TEST",
|
||||
"TEST_MODE",
|
||||
"APP_ERROR",
|
||||
"MAX",
|
||||
};
|
||||
|
||||
const char* SubGameStateNames[] =
|
||||
{
|
||||
"DATA_INITIALIZE",
|
||||
"SYSTEM_STARTUP",
|
||||
"SYSTEM_STARTUP_ERROR",
|
||||
"WARNING",
|
||||
"LOGO",
|
||||
"RATING",
|
||||
"DEMO",
|
||||
"TITLE",
|
||||
"RANKING",
|
||||
"SCORE_RANKING",
|
||||
"CM",
|
||||
"PHOTO_MODE_DEMO",
|
||||
"SELECTOR",
|
||||
"GAME_MAIN",
|
||||
"GAME_SEL",
|
||||
"STAGE_RESULT",
|
||||
"SCREEN_SHOT_SEL",
|
||||
"SCREEN_SHOT_RESULT",
|
||||
"GAME_OVER",
|
||||
"DATA_TEST_MAIN",
|
||||
"DATA_TEST_MISC",
|
||||
"DATA_TEST_OBJ",
|
||||
"DATA_TEST_STG",
|
||||
"DATA_TEST_MOT",
|
||||
"DATA_TEST_COLLISION",
|
||||
"DATA_TEST_SPR",
|
||||
"DATA_TEST_AET",
|
||||
"DATA_TEST_AUTH_3D",
|
||||
"DATA_TEST_CHR",
|
||||
"DATA_TEST_ITEM",
|
||||
"DATA_TEST_PERF",
|
||||
"DATA_TEST_PVSCRIPT",
|
||||
"DATA_TEST_PRINT",
|
||||
"DATA_TEST_CARD",
|
||||
"DATA_TEST_OPD",
|
||||
"DATA_TEST_SLIDER",
|
||||
"DATA_TEST_GLITTER",
|
||||
"DATA_TEST_GRAPHICS",
|
||||
"DATA_TEST_COLLECTION_CARD",
|
||||
"TEST_MODE_MAIN",
|
||||
"APP_ERROR",
|
||||
"MAX",
|
||||
};
|
||||
|
||||
const char* DataTestNames[] =
|
||||
{
|
||||
"MAIN TEST",
|
||||
"MISC TEST",
|
||||
"OBJECT TEST",
|
||||
"STAGE TEST",
|
||||
"MOTION TEST",
|
||||
"COLLISION TEST",
|
||||
"SPRITE TEST",
|
||||
"2DAUTH TEST",
|
||||
"3DAUTH TEST",
|
||||
"CHARA TEST",
|
||||
"ITEM TEST",
|
||||
"PERFORMANCE TEST",
|
||||
"PVSCRIPT TEST",
|
||||
"PRINT TEST",
|
||||
"CARD TEST",
|
||||
"OPD TEST",
|
||||
"SLIDER TEST",
|
||||
"GLITTER TEST",
|
||||
"GRAPHICS TEST",
|
||||
"COLLECTION CARD TEST",
|
||||
};
|
||||
|
||||
typedef void ChangeGameState(GameState);
|
||||
ChangeGameState* changeGameState = (ChangeGameState*)CHANGE_MODE_ADDRESS;
|
||||
|
||||
typedef void ChangeSubState(GameState, SubGameState);
|
||||
ChangeSubState* changeSubState = (ChangeSubState*)CHANGE_SUB_MODE_ADDRESS;
|
||||
|
||||
DebugComponent::DebugComponent()
|
||||
{
|
||||
}
|
||||
|
||||
DebugComponent::~DebugComponent()
|
||||
{
|
||||
}
|
||||
|
||||
const char* DebugComponent::GetDisplayName()
|
||||
{
|
||||
return "debug_component";
|
||||
}
|
||||
|
||||
void DebugComponent::Initialize(ComponentsManager*)
|
||||
{
|
||||
printf("[TLAC] DebugComponent::Initialize(): Initialized\n");
|
||||
|
||||
InjectPatches();
|
||||
|
||||
HWND consoleHandle = GetConsoleWindow();
|
||||
ShowWindow(consoleHandle, SW_SHOW);
|
||||
|
||||
// In case the FrameRateManager isn't enabled
|
||||
DWORD oldProtect;
|
||||
VirtualProtect((void*)AET_FRAME_DURATION_ADDRESS, sizeof(float), PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
}
|
||||
|
||||
void DebugComponent::Update()
|
||||
{
|
||||
if (dataTestMain)
|
||||
{
|
||||
Input::Keyboard::GetInstance()->PollInput();
|
||||
UpdateDataTestMain();
|
||||
}
|
||||
}
|
||||
|
||||
void DebugComponent::UpdateInput()
|
||||
{
|
||||
auto keyboard = Input::Keyboard::GetInstance();
|
||||
|
||||
// fast forward menus
|
||||
if (keyboard->IsDown(VK_SHIFT))
|
||||
{
|
||||
float* frameDuration = (float*)AET_FRAME_DURATION_ADDRESS;
|
||||
|
||||
if (keyboard->IsDown(VK_TAB))
|
||||
*frameDuration = 1.0f / (GetGameFrameRate() / aetSpeedUpFactor);
|
||||
else if (keyboard->IsReleased(VK_TAB))
|
||||
*frameDuration = 1.0f / 60.0f;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _countof(gameStateKeyMappings); i++)
|
||||
{
|
||||
if (keyboard->IsTapped(gameStateKeyMappings[i].KeyCode))
|
||||
InternalChangeGameState(gameStateKeyMappings[i].State);
|
||||
}
|
||||
}
|
||||
|
||||
void DebugComponent::InjectPatches()
|
||||
{
|
||||
const struct { void* Address; std::initializer_list<uint8_t> Data; } patches[] =
|
||||
{
|
||||
// Prevent the DATA_TEST game state from exiting on the first frame
|
||||
{ (void*)0x0000000140284B01, { 0x00 } },
|
||||
// Enable dw_gui sprite draw calls
|
||||
{ (void*)0x0000000140192601, { 0x00 } },
|
||||
// Update the dw_gui display
|
||||
{ (void*)0x0000000140302600, { 0xB0, 0x01 } },
|
||||
// Draw the dw_gui display
|
||||
{ (void*)0x0000000140302610, { 0xB0, 0x01 } },
|
||||
// Enable the dw_gui widgets
|
||||
{ (void*)0x0000000140192D00, { 0xB8, 0x01, 0x00, 0x00, 0x00, 0xC3 } },
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < _countof(patches); i++)
|
||||
InjectCode(patches[i].Address, patches[i].Data);
|
||||
}
|
||||
|
||||
void DebugComponent::SetConsoleForeground()
|
||||
{
|
||||
HWND consoleHandle = GetConsoleWindow();
|
||||
ShowWindow(consoleHandle, SW_SHOW);
|
||||
|
||||
if (consoleHandle == NULL)
|
||||
return;
|
||||
|
||||
WINDOWPLACEMENT place = { sizeof(WINDOWPLACEMENT) };
|
||||
GetWindowPlacement(consoleHandle, &place);
|
||||
|
||||
switch (place.showCmd)
|
||||
{
|
||||
case SW_SHOWMAXIMIZED:
|
||||
ShowWindow(consoleHandle, SW_SHOWMAXIMIZED);
|
||||
break;
|
||||
case SW_SHOWMINIMIZED:
|
||||
ShowWindow(consoleHandle, SW_RESTORE);
|
||||
break;
|
||||
default:
|
||||
ShowWindow(consoleHandle, SW_NORMAL);
|
||||
break;
|
||||
}
|
||||
|
||||
SetWindowPos(0, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE);
|
||||
SetForegroundWindow(consoleHandle);
|
||||
}
|
||||
|
||||
void DebugComponent::PrintDataTestMain()
|
||||
{
|
||||
system("cls");
|
||||
printf(" DATA TEST MAIN:\n\n");
|
||||
|
||||
for (int i = SUB_DATA_TEST_MISC; i <= SUB_DATA_TEST_COLLECTION_CARD; i++)
|
||||
printf("%s %s\n", i == selectionIndex ? "->" : " ", DataTestNames[i - SUB_DATA_TEST_MAIN]);
|
||||
|
||||
printf("\n");
|
||||
SetConsoleForeground();
|
||||
}
|
||||
|
||||
void DebugComponent::InternalChangeGameState(GameState state)
|
||||
{
|
||||
changeGameState(state);
|
||||
printDataTestMain = dataTestMain = (state == GS_DATA_TEST);
|
||||
}
|
||||
|
||||
void DebugComponent::UpdateDataTestMain()
|
||||
{
|
||||
auto keyboard = Input::Keyboard::GetInstance();
|
||||
|
||||
if (keyboard->IsIntervalTapped(VK_UP))
|
||||
{
|
||||
selectionIndex--;
|
||||
printDataTestMain = true;
|
||||
}
|
||||
|
||||
if (keyboard->IsIntervalTapped(VK_DOWN))
|
||||
{
|
||||
selectionIndex++;
|
||||
printDataTestMain = true;
|
||||
}
|
||||
|
||||
if (selectionIndex > SUB_DATA_TEST_COLLECTION_CARD)
|
||||
selectionIndex = SUB_DATA_TEST_MISC;
|
||||
|
||||
if (selectionIndex < SUB_DATA_TEST_MISC)
|
||||
selectionIndex = SUB_DATA_TEST_COLLECTION_CARD;
|
||||
|
||||
if (keyboard->IsTapped(VK_RETURN))
|
||||
{
|
||||
dataTestMain = false;
|
||||
|
||||
printf("[%s] -> [%s]\n", SubGameStateNames[SUB_DATA_TEST_MAIN], SubGameStateNames[selectionIndex]);
|
||||
changeSubState(GS_DATA_TEST, (SubGameState)selectionIndex);
|
||||
}
|
||||
|
||||
if (printDataTestMain)
|
||||
{
|
||||
PrintDataTestMain();
|
||||
printDataTestMain = false;
|
||||
}
|
||||
}
|
||||
|
||||
void DebugComponent::InjectCode(void* address, const std::initializer_list<uint8_t> &data)
|
||||
{
|
||||
const size_t byteCount = data.size() * sizeof(uint8_t);
|
||||
|
||||
DWORD oldProtect;
|
||||
VirtualProtect(address, byteCount, PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
|
||||
memcpy(address, data.begin(), byteCount);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
#include "EmulatorComponent.h"
|
||||
#include "GameState.h"
|
||||
#include "../Input/Keyboard/Keyboard.h"
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
class DebugComponent : public EmulatorComponent
|
||||
{
|
||||
public:
|
||||
DebugComponent();
|
||||
~DebugComponent();
|
||||
|
||||
virtual const char* GetDisplayName() override;
|
||||
|
||||
virtual void Initialize(ComponentsManager*) override;
|
||||
virtual void Update() override;
|
||||
virtual void UpdateInput() override;
|
||||
|
||||
private:
|
||||
const float aetSpeedUpFactor = 4.0f;
|
||||
|
||||
bool dataTestMain = false;
|
||||
bool printDataTestMain = false;
|
||||
int selectionIndex = SUB_DATA_TEST_MISC;
|
||||
|
||||
const struct { BYTE KeyCode; GameState State; } gameStateKeyMappings[5] =
|
||||
{
|
||||
{ VK_F4, GS_ADVERTISE },
|
||||
{ VK_F5, GS_GAME },
|
||||
{ VK_F6, GS_DATA_TEST },
|
||||
{ VK_F7, GS_TEST_MODE },
|
||||
{ VK_F8, GS_APP_ERROR },
|
||||
};
|
||||
|
||||
void InjectPatches();
|
||||
void SetConsoleForeground();
|
||||
void PrintDataTestMain();
|
||||
void InternalChangeGameState(GameState state);
|
||||
void UpdateDataTestMain();
|
||||
void InjectCode(void* address, const std::initializer_list<uint8_t> &data);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
#include "EmulatorComponent.h"
|
||||
#include "../Constants.h"
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
EmulatorComponent::EmulatorComponent()
|
||||
{
|
||||
}
|
||||
|
||||
EmulatorComponent::~EmulatorComponent()
|
||||
{
|
||||
}
|
||||
|
||||
void EmulatorComponent::SetElapsedTime(float value)
|
||||
{
|
||||
elapsedTime = value;
|
||||
}
|
||||
|
||||
float EmulatorComponent::GetElapsedTime()
|
||||
{
|
||||
return elapsedTime == 0.0f ? (1000.0f / 60.0f) : elapsedTime;
|
||||
}
|
||||
|
||||
float EmulatorComponent::GetFrameRate()
|
||||
{
|
||||
return 1000.0f / GetElapsedTime();
|
||||
}
|
||||
|
||||
float EmulatorComponent::GetGameFrameRate()
|
||||
{
|
||||
return *(float*)FRAME_RATE_ADDRESS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
class ComponentsManager;
|
||||
|
||||
class EmulatorComponent
|
||||
{
|
||||
public:
|
||||
EmulatorComponent();
|
||||
~EmulatorComponent();
|
||||
|
||||
virtual const char* GetDisplayName() = 0;
|
||||
|
||||
virtual void Initialize(ComponentsManager*) = 0;
|
||||
virtual void Update() = 0;
|
||||
|
||||
virtual void UpdateInput() {};
|
||||
virtual void OnFocusGain() {};
|
||||
virtual void OnFocusLost() {};
|
||||
|
||||
void SetElapsedTime(float value);
|
||||
float GetElapsedTime();
|
||||
float GetFrameRate();
|
||||
float GetGameFrameRate();
|
||||
|
||||
private:
|
||||
float elapsedTime;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
#include "FPSLimiter.h"
|
||||
#include <Windows.h>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <tchar.h>
|
||||
|
||||
using dsec = std::chrono::duration<double>;
|
||||
using seconds = std::chrono::seconds;
|
||||
|
||||
// this is pretty much just lybxlpsv's limiter, but removed from GLComponent
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
using namespace std::chrono;
|
||||
|
||||
static std::chrono::time_point mBeginFrame = system_clock::now();
|
||||
static std::chrono::time_point prevTimeInSeconds = time_point_cast<seconds>(mBeginFrame);
|
||||
|
||||
const LPCTSTR config_file_name = _T(".\\config.ini");
|
||||
int fpsLimit = GetPrivateProfileIntW(L"graphics", L"fps.limit", 0, config_file_name);
|
||||
|
||||
FPSLimiter::FPSLimiter()
|
||||
{
|
||||
}
|
||||
|
||||
FPSLimiter::~FPSLimiter()
|
||||
{
|
||||
}
|
||||
|
||||
const char* FPSLimiter::GetDisplayName()
|
||||
{
|
||||
return "fps_limiter";
|
||||
}
|
||||
|
||||
void FPSLimiter::Initialize(ComponentsManager* manager)
|
||||
{
|
||||
mBeginFrame = std::chrono::system_clock::now();
|
||||
prevTimeInSeconds = std::chrono::time_point_cast<seconds>(mBeginFrame);
|
||||
frameCountPerSecond = 0;
|
||||
if(fpsLimit != 0)
|
||||
printf("FPSLimiter fpsLimit: %d\n", fpsLimit);
|
||||
}
|
||||
|
||||
// I assume this gets called once per frame... if not this won't work
|
||||
void FPSLimiter::Update()
|
||||
{
|
||||
auto invFpsLimit = round<std::chrono::system_clock::duration>(dsec{ 1. / fpsLimit });
|
||||
auto mEndFrame = mBeginFrame + invFpsLimit;
|
||||
auto timeInSeconds = std::chrono::time_point_cast<seconds>(std::chrono::system_clock::now());
|
||||
|
||||
++frameCountPerSecond;
|
||||
if (timeInSeconds > prevTimeInSeconds)
|
||||
{
|
||||
//printf("FPSLimiter::Update(): FPS: %d\n", frameCountPerSecond);
|
||||
frameCountPerSecond = 0;
|
||||
prevTimeInSeconds = timeInSeconds;
|
||||
}
|
||||
|
||||
// This part keeps the frame rate.
|
||||
if (fpsLimit > 19) // not sure why lyb used 19 here
|
||||
std::this_thread::sleep_until(mEndFrame);
|
||||
mBeginFrame = mEndFrame;
|
||||
mEndFrame = mBeginFrame + invFpsLimit;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
#include "EmulatorComponent.h"
|
||||
#include <chrono>
|
||||
|
||||
using seconds = std::chrono::seconds;
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
class FPSLimiter : public EmulatorComponent
|
||||
{
|
||||
public:
|
||||
FPSLimiter();
|
||||
~FPSLimiter();
|
||||
|
||||
virtual const char* GetDisplayName() override;
|
||||
|
||||
virtual void Initialize(ComponentsManager*) override;
|
||||
virtual void Update() override;
|
||||
|
||||
private:
|
||||
int frameCountPerSecond;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
#include "FastLoader.h"
|
||||
#include "../Constants.h"
|
||||
#include <stdio.h>
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
FastLoader::FastLoader()
|
||||
{
|
||||
}
|
||||
|
||||
FastLoader::~FastLoader()
|
||||
{
|
||||
}
|
||||
|
||||
const char* FastLoader::GetDisplayName()
|
||||
{
|
||||
return "fast_loader";
|
||||
}
|
||||
|
||||
void FastLoader::Initialize(ComponentsManager*)
|
||||
{
|
||||
}
|
||||
|
||||
void FastLoader::Update()
|
||||
{
|
||||
if (dataInitialized)
|
||||
return;
|
||||
|
||||
previousGameState = currentGameState;
|
||||
currentGameState = *(GameState*)CURRENT_GAME_STATE_ADDRESS;
|
||||
|
||||
if (currentGameState == GS_STARTUP)
|
||||
{
|
||||
typedef void UpdateTask();
|
||||
UpdateTask* updateTask = (UpdateTask*)UPDATE_TASKS_ADDRESS;
|
||||
|
||||
// speed up TaskSystemStartup
|
||||
for (int i = 0; i < updatesPerFrame; i++)
|
||||
updateTask();
|
||||
|
||||
constexpr int DATA_INITIALIZED = 3;
|
||||
|
||||
// skip TaskDataInit
|
||||
*(int*)(DATA_INIT_STATE_ADDRESS) = DATA_INITIALIZED;
|
||||
|
||||
// skip TaskWarning
|
||||
*(int*)(SYSTEM_WARNING_ELAPSED_ADDRESS) = 3939;
|
||||
}
|
||||
else if (previousGameState == GS_STARTUP)
|
||||
{
|
||||
dataInitialized = true;
|
||||
printf("[TLAC] FastLoader::Update(): Data Initialized\n");
|
||||
}
|
||||
}
|
||||
|
||||
void FastLoader::UpdateInput()
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
#include "EmulatorComponent.h"
|
||||
#include "GameState.h"
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
class FastLoader : public EmulatorComponent
|
||||
{
|
||||
public:
|
||||
FastLoader();
|
||||
~FastLoader();
|
||||
|
||||
virtual const char* GetDisplayName() override;
|
||||
|
||||
virtual void Initialize(ComponentsManager*) override;
|
||||
virtual void Update() override;
|
||||
virtual void UpdateInput() override;
|
||||
|
||||
private:
|
||||
const int updatesPerFrame = 39;
|
||||
|
||||
GameState currentGameState;
|
||||
GameState previousGameState;
|
||||
bool dataInitialized = false;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
#include "FrameRateManager.h"
|
||||
#include "../Constants.h"
|
||||
#include "GameState.h"
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#include "../framework.h"
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
FrameRateManager::FrameRateManager()
|
||||
{
|
||||
}
|
||||
|
||||
FrameRateManager::~FrameRateManager()
|
||||
{
|
||||
}
|
||||
|
||||
const char* FrameRateManager::GetDisplayName()
|
||||
{
|
||||
return "frame_rate_manager";
|
||||
}
|
||||
|
||||
void FrameRateManager::Initialize(ComponentsManager*)
|
||||
{
|
||||
pvFrameRate = (float*)PV_FRAME_RATE_ADDRESS;
|
||||
frameSpeed = (float*)FRAME_SPEED_ADDRESS;
|
||||
aetFrameDuration = (float*)AET_FRAME_DURATION_ADDRESS;
|
||||
|
||||
// The default is expected to be 1.0 / 60.0
|
||||
defaultAetFrameDuration = *aetFrameDuration;
|
||||
|
||||
// This const variable is stored inside a data segment so we don't want to throw any access violations
|
||||
DWORD oldProtect;
|
||||
VirtualProtect((void*)AET_FRAME_DURATION_ADDRESS, sizeof(float), PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
}
|
||||
|
||||
void FrameRateManager::Update()
|
||||
{
|
||||
float frameRate = 0.0f;
|
||||
frameRate = RoundFrameRate(GetGameFrameRate());
|
||||
|
||||
*aetFrameDuration = 1.0f / frameRate;
|
||||
*pvFrameRate = frameRate;
|
||||
|
||||
bool inGame = *(GameState*)CURRENT_GAME_STATE_ADDRESS == GS_GAME;
|
||||
|
||||
if (inGame)
|
||||
{
|
||||
// During the GAME state the frame rate will be handled by the PvFrameRate instead
|
||||
|
||||
constexpr float defaultFrameSpeed = 1.0f;
|
||||
constexpr float defaultFrameRate = 60.0f;
|
||||
|
||||
// This PV struct creates a copy of the PvFrameRate & PvFrameSpeed during the loading screen
|
||||
// so we'll make sure to keep updating it as well.
|
||||
// Each new motion also creates its own copy of these values but keeping track of the active motions is annoying
|
||||
// and they usually change multiple times per PV anyway so this should suffice for now
|
||||
float* pvStructPvFrameRate = (float*)(0x0000000140CDD978 + 0x2BF98);
|
||||
float* pvStructPvFrameSpeed = (float*)(0x0000000140CDD978 + 0x2BF9C);
|
||||
|
||||
*pvStructPvFrameRate = *pvFrameRate;
|
||||
*pvStructPvFrameSpeed = (defaultFrameRate / *pvFrameRate);
|
||||
|
||||
*frameSpeed = defaultFrameSpeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
*frameSpeed = *aetFrameDuration / defaultAetFrameDuration;
|
||||
}
|
||||
}
|
||||
|
||||
float FrameRateManager::RoundFrameRate(float frameRate)
|
||||
{
|
||||
constexpr float roundingThreshold = 4.0f;
|
||||
|
||||
for (int i = 0; i < sizeof(commonRefreshRates) / sizeof(float); i++)
|
||||
{
|
||||
float refreshRate = commonRefreshRates[i];
|
||||
|
||||
if (frameRate > refreshRate - roundingThreshold && frameRate < refreshRate + roundingThreshold)
|
||||
frameRate = refreshRate;
|
||||
}
|
||||
|
||||
return frameRate;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
#include "EmulatorComponent.h"
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
class FrameRateManager : public EmulatorComponent
|
||||
{
|
||||
public:
|
||||
FrameRateManager();
|
||||
~FrameRateManager();
|
||||
|
||||
virtual const char* GetDisplayName() override;
|
||||
|
||||
virtual void Initialize(ComponentsManager*) override;
|
||||
virtual void Update() override;
|
||||
|
||||
private:
|
||||
float *pvFrameRate;
|
||||
float *frameSpeed;
|
||||
float *aetFrameDuration;
|
||||
float defaultAetFrameDuration;
|
||||
|
||||
float commonRefreshRates[5]
|
||||
{
|
||||
60.0f,
|
||||
75.0f,
|
||||
120.0f,
|
||||
144.0f,
|
||||
240.0f,
|
||||
};
|
||||
|
||||
float RoundFrameRate(float frameRate);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
enum GameState : uint32_t
|
||||
{
|
||||
GS_STARTUP,
|
||||
GS_ADVERTISE,
|
||||
GS_GAME,
|
||||
GS_DATA_TEST,
|
||||
GS_TEST_MODE,
|
||||
GS_APP_ERROR,
|
||||
GS_MAX,
|
||||
};
|
||||
|
||||
enum SubGameState : uint32_t
|
||||
{
|
||||
SUB_DATA_INITIALIZE,
|
||||
SUB_SYSTEM_STARTUP,
|
||||
SUB_SYSTEM_STARTUP_ERROR,
|
||||
SUB_WARNING,
|
||||
SUB_LOGO,
|
||||
SUB_RATING,
|
||||
SUB_DEMO,
|
||||
SUB_TITLE,
|
||||
SUB_RANKING,
|
||||
SUB_SCORE_RANKING,
|
||||
SUB_CM,
|
||||
SUB_PHOTO_MODE_DEMO,
|
||||
SUB_SELECTOR,
|
||||
SUB_GAME_MAIN,
|
||||
SUB_GAME_SEL,
|
||||
SUB_STAGE_RESULT,
|
||||
SUB_SCREEN_SHOT_SEL,
|
||||
SUB_SCREEN_SHOT_RESULT,
|
||||
SUB_GAME_OVER,
|
||||
SUB_DATA_TEST_MAIN,
|
||||
SUB_DATA_TEST_MISC,
|
||||
SUB_DATA_TEST_OBJ,
|
||||
SUB_DATA_TEST_STG,
|
||||
SUB_DATA_TEST_MOT,
|
||||
SUB_DATA_TEST_COLLISION,
|
||||
SUB_DATA_TEST_SPR,
|
||||
SUB_DATA_TEST_AET,
|
||||
SUB_DATA_TEST_AUTH_3D,
|
||||
SUB_DATA_TEST_CHR,
|
||||
SUB_DATA_TEST_ITEM,
|
||||
SUB_DATA_TEST_PERF,
|
||||
SUB_DATA_TEST_PVSCRIPT,
|
||||
SUB_DATA_TEST_PRINT,
|
||||
SUB_DATA_TEST_CARD,
|
||||
SUB_DATA_TEST_OPD,
|
||||
SUB_DATA_TEST_SLIDER,
|
||||
SUB_DATA_TEST_GLITTER,
|
||||
SUB_DATA_TEST_GRAPHICS,
|
||||
SUB_DATA_TEST_COLLECTION_CARD,
|
||||
SUB_TEST_MODE_MAIN,
|
||||
SUB_APP_ERROR,
|
||||
SUB_MAX,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
enum HoldState
|
||||
{
|
||||
HOLD_NONE,
|
||||
HOLD_SANKAKU = 64,
|
||||
HOLD_MARU = 128,
|
||||
HOLD_BATSU = 256,
|
||||
HOLD_SHIKAKU = 512,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
enum TargetHitStates
|
||||
{
|
||||
COOL,
|
||||
FINE,
|
||||
SAFE,
|
||||
SAD,
|
||||
COOL_WRONG, // unsure
|
||||
FINE_WRONG, // unsure
|
||||
SAFE_WRONG, // unsure
|
||||
SAD_WRONG, // unsure
|
||||
WORST,
|
||||
NONE = 21,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
#include "TargetInspector.h"
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
bool TargetInspector::repressTbl[maxTargetSlots];
|
||||
|
||||
TargetInspector::TargetInspector()
|
||||
{
|
||||
}
|
||||
|
||||
TargetInspector::~TargetInspector()
|
||||
{
|
||||
}
|
||||
|
||||
void TargetInspector::Initialize(ComponentsManager*)
|
||||
{
|
||||
tgtTypePtr = (int*)TGT_TYPE_BASE_ADDRESS;
|
||||
tgtHitStatePtr = (int*)TGT_HIT_STATE_BASE_ADDRESS;
|
||||
tgtRemainingTimePtr = (float*)TGT_REMAINING_DURATION_BASE_ADDRESS;
|
||||
}
|
||||
|
||||
void TargetInspector::Update()
|
||||
{
|
||||
GetTargetStates();
|
||||
UpdateRepressTbl();
|
||||
}
|
||||
|
||||
const char* TargetInspector::GetDisplayName()
|
||||
{
|
||||
return "target_inspector";
|
||||
}
|
||||
|
||||
void TargetInspector::GetTargetStates()
|
||||
{
|
||||
for (int i = 0; i < maxTargetSlots; ++i)
|
||||
{
|
||||
tgtStates[i].tgtType = *((int*)((char*)tgtTypePtr + (i * offset)));
|
||||
tgtStates[i].tgtHitState = *((int*)((char*)tgtHitStatePtr + (i * offset)));
|
||||
tgtStates[i].tgtRemainingTime = *((float*)((char*)tgtRemainingTimePtr + (i * offset)));
|
||||
}
|
||||
}
|
||||
|
||||
void TargetInspector::UpdateRepressTbl()
|
||||
{
|
||||
for (int i = 0; i < maxTargetSlots; ++i)
|
||||
{
|
||||
repressTbl[i] = IsWithinRange(tgtStates[i].tgtRemainingTime)
|
||||
&& HasNotBeenHit(tgtStates[i].tgtHitState)
|
||||
&& !IsSlide(tgtStates[i].tgtType);
|
||||
}
|
||||
}
|
||||
|
||||
bool TargetInspector::IsWithinRange(float time)
|
||||
{
|
||||
return time < timingThreshold && time > -timingThreshold && time != 0;
|
||||
}
|
||||
|
||||
bool TargetInspector::HasNotBeenHit(int hitState)
|
||||
{
|
||||
return hitState == NONE;
|
||||
}
|
||||
|
||||
bool TargetInspector::IsSlide(int type)
|
||||
{
|
||||
return (type >= SLIDE_L && type <= SLIDE_LONG_R) || type >= SLIDE_L_CH;
|
||||
}
|
||||
|
||||
bool TargetInspector::IsAnyRepress()
|
||||
{
|
||||
for (int i = 0; i < maxTargetSlots; ++i)
|
||||
{
|
||||
if (repressTbl[i])
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
#include "../EmulatorComponent.h"
|
||||
#include "../Input/InputEmulator.h"
|
||||
#include "../../Constants.h"
|
||||
#include "TargetHitStates.h"
|
||||
#include "TargetState.h"
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
const int maxTargetSlots = 32;
|
||||
|
||||
class TargetInspector : public EmulatorComponent
|
||||
{
|
||||
public:
|
||||
TargetInspector();
|
||||
~TargetInspector();
|
||||
|
||||
static bool repressTbl[maxTargetSlots];
|
||||
|
||||
virtual void Initialize(ComponentsManager*) override;
|
||||
virtual void Update() override;
|
||||
virtual const char* GetDisplayName() override;
|
||||
|
||||
void GetTargetStates();
|
||||
static bool IsAnyRepress();
|
||||
|
||||
private:
|
||||
const uint64_t offset = 0x4A8;
|
||||
const float timingThreshold = 0.13f; // PS4 estimate
|
||||
|
||||
TargetState tgtStates[maxTargetSlots];
|
||||
|
||||
int* tgtTypePtr;
|
||||
int* tgtHitStatePtr;
|
||||
float* tgtRemainingTimePtr;
|
||||
|
||||
bool IsSlide(int);
|
||||
bool IsWithinRange(float);
|
||||
bool HasNotBeenHit(int);
|
||||
void UpdateRepressTbl();
|
||||
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
struct TargetState
|
||||
{
|
||||
int tgtType;
|
||||
int tgtHitState;
|
||||
float tgtRemainingTime;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
enum TargetTypes
|
||||
{
|
||||
SANKAKU,
|
||||
MARU,
|
||||
BATSU,
|
||||
SHIKAKU,
|
||||
SANKAKU_H,
|
||||
MARU_H,
|
||||
BATSU_H,
|
||||
SHIKAKU_H,
|
||||
SLIDE_L = 12,
|
||||
SLIDE_R,
|
||||
SLIDE_LONG_L = 15,
|
||||
SLIDE_LONG_R,
|
||||
SANKAKU_CH = 18,
|
||||
MARU_CH,
|
||||
BATSU_CH,
|
||||
SHIKAKU_CH,
|
||||
SLIDE_L_CH = 23,
|
||||
SLIDE_R_CH,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
enum InputBufferType
|
||||
{
|
||||
InputBufferType_Tapped,
|
||||
InputBufferType_Released,
|
||||
InputBufferType_Down,
|
||||
InputBufferType_DoubleTapped,
|
||||
InputBufferType_IntervalTapped,
|
||||
InputBufferType_Max,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,308 @@
|
||||
#include <iostream>
|
||||
#include "windows.h"
|
||||
#include "InputEmulator.h"
|
||||
#include "../ComponentsManager.h"
|
||||
#include "../../Constants.h"
|
||||
#include "../../framework.h"
|
||||
#include "../../Input/Bindings/KeyboardBinding.h"
|
||||
#include "../../Input/Bindings/XinputBinding.h"
|
||||
#include "../../Input/Bindings/MouseBinding.h"
|
||||
#include "../../Input/Bindings/Ds4Binding.h"
|
||||
#include "../../Input/KeyConfig/Config.h"
|
||||
#include "../../Utilities/Operations.h"
|
||||
#include "../../Utilities/EnumBitwiseOperations.h"
|
||||
#include "../../FileSystem/ConfigFile.h"
|
||||
|
||||
const std::string KEY_CONFIG_FILE_NAME = "keyconfig.ini";
|
||||
|
||||
using namespace TLAC::Input;
|
||||
using namespace TLAC::Input::KeyConfig;
|
||||
using namespace TLAC::Utilities;
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
|
||||
InputEmulator::InputEmulator()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
InputEmulator::~InputEmulator()
|
||||
{
|
||||
delete TestBinding;
|
||||
delete ServiceBinding;
|
||||
|
||||
delete StartBinding;
|
||||
delete SankakuBinding;
|
||||
delete ShikakuBinding;
|
||||
delete BatsuBinding;
|
||||
delete MaruBinding;
|
||||
|
||||
delete LeftBinding;
|
||||
delete RightBinding;
|
||||
}
|
||||
|
||||
const char* InputEmulator::GetDisplayName()
|
||||
{
|
||||
return "input_emulator";
|
||||
}
|
||||
|
||||
void InputEmulator::Initialize(ComponentsManager* manager)
|
||||
{
|
||||
componentsManager = manager;
|
||||
componentsManager->SetIsInputEmulatorUsed(true);
|
||||
|
||||
inputState = GetInputStatePtr((void*)INPUT_STATE_PTR_ADDRESS);
|
||||
inputState->HideCursor();
|
||||
|
||||
TestBinding = new Binding();
|
||||
ServiceBinding = new Binding();
|
||||
StartBinding = new Binding();
|
||||
|
||||
SankakuBinding = new Binding();
|
||||
ShikakuBinding = new Binding();
|
||||
BatsuBinding = new Binding();
|
||||
MaruBinding = new Binding();
|
||||
|
||||
LeftBinding = new Binding();
|
||||
RightBinding = new Binding();
|
||||
|
||||
FileSystem::ConfigFile configFile(framework::GetModuleDirectory(), KEY_CONFIG_FILE_NAME);
|
||||
configFile.OpenRead();
|
||||
|
||||
Config::BindConfigKeys(configFile.ConfigMap, "JVS_TEST", *TestBinding, { "F1" });
|
||||
Config::BindConfigKeys(configFile.ConfigMap, "JVS_SERVICE", *ServiceBinding, { "F2" });
|
||||
Config::BindConfigKeys(configFile.ConfigMap, "JVS_START", *StartBinding, { "Enter" });
|
||||
Config::BindConfigKeys(configFile.ConfigMap, "JVS_TRIANGLE", *SankakuBinding, { "W", "I" });
|
||||
Config::BindConfigKeys(configFile.ConfigMap, "JVS_SQUARE", *ShikakuBinding, { "A", "J" });
|
||||
Config::BindConfigKeys(configFile.ConfigMap, "JVS_CROSS", *BatsuBinding, { "S", "K" });
|
||||
Config::BindConfigKeys(configFile.ConfigMap, "JVS_CIRCLE", *MaruBinding, { "D", "L" });
|
||||
Config::BindConfigKeys(configFile.ConfigMap, "JVS_LEFT", *LeftBinding, { "Q", "U" });
|
||||
Config::BindConfigKeys(configFile.ConfigMap, "JVS_RIGHT", *RightBinding, { "E", "O" });
|
||||
|
||||
mouseScrollPvSelection = configFile.GetBooleanValue("mouse_scroll_pv_selection");
|
||||
}
|
||||
|
||||
void InputEmulator::Update()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void InputEmulator::OnFocusLost()
|
||||
{
|
||||
// to prevent buttons from being "stuck"
|
||||
inputState->ClearState();
|
||||
inputState->HideCursor();
|
||||
}
|
||||
|
||||
void InputEmulator::UpdateInput()
|
||||
{
|
||||
if (!componentsManager->GetUpdateGameInput())
|
||||
return;
|
||||
|
||||
if (!componentsManager->IsDwGuiActive())
|
||||
{
|
||||
UpdateJvsInput();
|
||||
|
||||
if (mouseScrollPvSelection && !componentsManager->IsDwGuiHovered())
|
||||
UpdateMousePvScroll();
|
||||
}
|
||||
|
||||
UpdateDwGuiInput();
|
||||
}
|
||||
|
||||
void InputEmulator::UpdateJvsInput()
|
||||
{
|
||||
auto tappedFunc = [](void* binding) { return ((Binding*)binding)->AnyTapped(); };
|
||||
auto releasedFunc = [](void* binding) { return ((Binding*)binding)->AnyReleased(); };
|
||||
auto downFunc = [](void* binding) { return ((Binding*)binding)->AnyDown(); };
|
||||
|
||||
lastDownState = inputState->Down.Buttons;
|
||||
|
||||
inputState->Tapped.Buttons = GetJvsButtonsState(tappedFunc);
|
||||
inputState->Released.Buttons = GetJvsButtonsState(releasedFunc);
|
||||
inputState->Down.Buttons = GetJvsButtonsState(downFunc);
|
||||
inputState->DoubleTapped.Buttons = GetJvsButtonsState(tappedFunc);
|
||||
inputState->IntervalTapped.Buttons = GetJvsButtonsState(tappedFunc);
|
||||
|
||||
UpdateHoldState();
|
||||
heldButtons = GetButtonFromHold();
|
||||
|
||||
if ((lastDownState &= inputState->Tapped.Buttons) != 0)
|
||||
{
|
||||
inputState->Down.Buttons ^= inputState->Tapped.Buttons;
|
||||
if (IsHold() && !TargetInspector::IsAnyRepress())
|
||||
inputState->Down.Buttons |= heldButtons;
|
||||
}
|
||||
|
||||
// repress held down buttons to not block input
|
||||
//inputState->Down.Buttons ^= inputState->Tapped.Buttons;
|
||||
}
|
||||
|
||||
HoldState InputEmulator::GetHoldState()
|
||||
{
|
||||
return (HoldState) * ((int*)HOLD_STATE_ADDRESS);
|
||||
}
|
||||
|
||||
int InputEmulator::GetMaxHoldState()
|
||||
{
|
||||
return *(int*)MAX_HOLD_STATE_ADDRESS;
|
||||
}
|
||||
|
||||
bool InputEmulator::IsHold()
|
||||
{
|
||||
return ((holdState != HOLD_NONE) && (GetMaxHoldState() != 1));
|
||||
}
|
||||
|
||||
void InputEmulator::UpdateHoldState()
|
||||
{
|
||||
holdState = GetHoldState();
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
int holdId = 1 << (i + 6);
|
||||
|
||||
if ((holdId & holdState) != 0)
|
||||
holdTbl[i] = 1;
|
||||
else
|
||||
holdTbl[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void InputEmulator::UpdateDwGuiInput()
|
||||
{
|
||||
auto keyboard = Keyboard::GetInstance();
|
||||
auto mouse = Mouse::GetInstance();
|
||||
|
||||
auto pos = mouse->GetRelativePosition();
|
||||
inputState->MouseX = (int)pos.x;
|
||||
inputState->MouseY = (int)pos.y;
|
||||
|
||||
auto deltaPos = mouse->GetDeltaPosition();
|
||||
inputState->MouseDeltaX = (int)deltaPos.x;
|
||||
inputState->MouseDeltaY = (int)deltaPos.y;
|
||||
|
||||
inputState->Key = GetKeyState();
|
||||
|
||||
for (int i = 0; i < sizeof(keyBits) / sizeof(KeyBit); i++)
|
||||
UpdateInputBit(keyBits[i].Bit, keyBits[i].KeyCode);
|
||||
|
||||
for (int i = InputBufferType_Tapped; i < InputBufferType_Max; i++)
|
||||
{
|
||||
inputState->SetBit(scrollUpBit, mouse->GetIsScrolledUp(), (InputBufferType)i);
|
||||
inputState->SetBit(scrollDownBit, mouse->GetIsScrolledDown(), (InputBufferType)i);
|
||||
}
|
||||
}
|
||||
|
||||
void InputEmulator::UpdateMousePvScroll()
|
||||
{
|
||||
// I originally wanted to use a MouseBinding set to JVS_LEFT / JVS_RIGHT
|
||||
// but that ended up being too slow because a PV slot can only be scrolled to once the scroll animation has finished playing
|
||||
int* slotsToScroll = (int*)PV_SEL_SLOTS_TO_SCROLL;
|
||||
int* modulesToScroll = (int*)MODULE_SEL_SLOTS_TO_SCROLL;
|
||||
|
||||
auto mouse = Mouse::GetInstance();
|
||||
if (mouse->GetIsScrolledUp())
|
||||
{
|
||||
if (*(int*)PV_SEL_SLOTS_CONST < 26) *slotsToScroll -= 1;
|
||||
if (*(int*)MODULE_IS_RECOMMENDED == 0) *modulesToScroll -= 1;
|
||||
}
|
||||
if (mouse->GetIsScrolledDown())
|
||||
{
|
||||
if (*(int*)PV_SEL_SLOTS_CONST < 26) *slotsToScroll += 1;
|
||||
if (*(int*)MODULE_IS_RECOMMENDED == 0) *modulesToScroll += 1;
|
||||
}
|
||||
}
|
||||
|
||||
InputState* InputEmulator::GetInputStatePtr(void* address)
|
||||
{
|
||||
return (InputState*)(*(uint64_t*)address);
|
||||
}
|
||||
|
||||
JvsButtons InputEmulator::GetJvsButtonsState(bool(*buttonTestFunc)(void*))
|
||||
{
|
||||
JvsButtons buttons = JVS_NONE;
|
||||
|
||||
if (buttonTestFunc(TestBinding))
|
||||
buttons |= JVS_TEST;
|
||||
if (buttonTestFunc(ServiceBinding))
|
||||
buttons |= JVS_SERVICE;
|
||||
|
||||
if (buttonTestFunc(StartBinding))
|
||||
buttons |= JVS_START;
|
||||
|
||||
if (buttonTestFunc(SankakuBinding))
|
||||
buttons |= JVS_TRIANGLE;
|
||||
if (buttonTestFunc(ShikakuBinding))
|
||||
buttons |= JVS_SQUARE;
|
||||
if (buttonTestFunc(BatsuBinding))
|
||||
buttons |= JVS_CROSS;
|
||||
if (buttonTestFunc(MaruBinding))
|
||||
buttons |= JVS_CIRCLE;
|
||||
|
||||
if (buttonTestFunc(LeftBinding))
|
||||
buttons |= JVS_L;
|
||||
if (buttonTestFunc(RightBinding))
|
||||
buttons |= JVS_R;
|
||||
|
||||
return buttons;
|
||||
}
|
||||
|
||||
JvsButtons InputEmulator::GetButtonFromHold()
|
||||
{
|
||||
JvsButtons buttons = JVS_NONE;
|
||||
|
||||
if (holdTbl[0])
|
||||
buttons |= JVS_TRIANGLE;
|
||||
if (holdTbl[1])
|
||||
buttons |= JVS_CIRCLE;
|
||||
if (holdTbl[2])
|
||||
buttons |= JVS_CROSS;
|
||||
if (holdTbl[3])
|
||||
buttons |= JVS_SQUARE;
|
||||
|
||||
return buttons;
|
||||
}
|
||||
|
||||
char InputEmulator::GetKeyState()
|
||||
{
|
||||
auto keyboard = Keyboard::GetInstance();
|
||||
|
||||
bool upper = keyboard->IsDown(VK_SHIFT);
|
||||
constexpr char caseDifference = 'A' - 'a';
|
||||
|
||||
char inputKey = 0x00;
|
||||
|
||||
for (char key = '0'; key < 'Z'; key++)
|
||||
{
|
||||
if (keyboard->IsIntervalTapped(key))
|
||||
inputKey = (upper || key < 'A') ? key : (key - caseDifference);
|
||||
}
|
||||
|
||||
if (keyboard->IsIntervalTapped(VK_BACK))
|
||||
inputKey = 0x08;
|
||||
|
||||
if (keyboard->IsIntervalTapped(VK_TAB))
|
||||
inputKey = 0x09;
|
||||
|
||||
if (keyboard->IsIntervalTapped(VK_SPACE))
|
||||
inputKey = 0x20;
|
||||
|
||||
if (keyboard->IsIntervalTapped(VK_ESCAPE))
|
||||
exit(0);
|
||||
|
||||
return inputKey;
|
||||
}
|
||||
|
||||
void InputEmulator::UpdateInputBit(uint32_t bit, uint8_t keycode)
|
||||
{
|
||||
auto keyboard = Keyboard::GetInstance();
|
||||
|
||||
inputState->SetBit(bit, keyboard->IsTapped(keycode), InputBufferType_Tapped);
|
||||
inputState->SetBit(bit, keyboard->IsReleased(keycode), InputBufferType_Released);
|
||||
inputState->SetBit(bit, keyboard->IsDown(keycode), InputBufferType_Down);
|
||||
inputState->SetBit(bit, keyboard->IsDoubleTapped(keycode), InputBufferType_DoubleTapped);
|
||||
inputState->SetBit(bit, keyboard->IsIntervalTapped(keycode), InputBufferType_IntervalTapped);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include <Windows.h>
|
||||
#include "InputState.h"
|
||||
#include "../EmulatorComponent.h"
|
||||
#include "../../Input/Bindings/Binding.h"
|
||||
#include "../GameTargets/TargetTypes.h"
|
||||
#include "../GameTargets/TargetHitStates.h"
|
||||
#include "../GameTargets/HoldState.h"
|
||||
#include "../GameTargets/TargetInspector.h"
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
struct KeyBit
|
||||
{
|
||||
uint32_t Bit;
|
||||
uint8_t KeyCode;
|
||||
};
|
||||
|
||||
class InputEmulator : public EmulatorComponent
|
||||
{
|
||||
public:
|
||||
Input::Binding* TestBinding;
|
||||
Input::Binding* ServiceBinding;
|
||||
|
||||
Input::Binding* StartBinding;
|
||||
Input::Binding* SankakuBinding;
|
||||
Input::Binding* ShikakuBinding;
|
||||
Input::Binding* BatsuBinding;
|
||||
Input::Binding* MaruBinding;
|
||||
|
||||
Input::Binding* LeftBinding;
|
||||
Input::Binding* RightBinding;
|
||||
|
||||
InputEmulator();
|
||||
~InputEmulator();
|
||||
|
||||
virtual const char* GetDisplayName() override;
|
||||
|
||||
virtual void Initialize(ComponentsManager*) override;
|
||||
virtual void Update() override;
|
||||
virtual void UpdateInput() override;
|
||||
|
||||
virtual void OnFocusLost() override;
|
||||
|
||||
private:
|
||||
ComponentsManager* componentsManager;
|
||||
|
||||
bool mouseScrollPvSelection = false;
|
||||
const uint32_t scrollUpBit = 99;
|
||||
const uint32_t scrollDownBit = 100;
|
||||
|
||||
KeyBit keyBits[20] =
|
||||
{
|
||||
{ 5, VK_LEFT },
|
||||
{ 6, VK_RIGHT },
|
||||
|
||||
{ 29, VK_SPACE },
|
||||
{ 39, 'A' },
|
||||
{ 43, 'E' },
|
||||
{ 42, 'D' },
|
||||
{ 55, 'Q' },
|
||||
{ 57, 'S' }, // unsure
|
||||
{ 61, 'W' },
|
||||
{ 63, 'Y' },
|
||||
{ 84, 'L' }, // unsure
|
||||
|
||||
{ 80, VK_RETURN },
|
||||
{ 81, VK_SHIFT },
|
||||
{ 82, VK_CONTROL },
|
||||
{ 83, VK_MENU },
|
||||
|
||||
{ 91, VK_UP },
|
||||
{ 93, VK_DOWN },
|
||||
|
||||
{ 96, MK_LBUTTON },
|
||||
{ 97, VK_MBUTTON },
|
||||
{ 98, MK_RBUTTON },
|
||||
};
|
||||
|
||||
InputState* inputState;
|
||||
JvsButtons lastDownState;
|
||||
JvsButtons heldButtons;
|
||||
|
||||
int holdTbl[4];
|
||||
HoldState holdState;
|
||||
|
||||
void UpdateJvsInput();
|
||||
void UpdateDwGuiInput();
|
||||
void UpdateMousePvScroll();
|
||||
void UpdateHoldState();
|
||||
InputState* GetInputStatePtr(void* address);
|
||||
JvsButtons GetJvsButtonsState(bool(*buttonTestFunc)(void*));
|
||||
JvsButtons GetButtonFromHold();
|
||||
char GetKeyState();
|
||||
HoldState GetHoldState();
|
||||
int GetMaxHoldState();
|
||||
bool IsHold();
|
||||
|
||||
void UpdateInputBit(uint32_t bit, uint8_t keycode);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
#include "InputState.h"
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
void InputState::ClearState()
|
||||
{
|
||||
memset(this, 0, sizeof(InputState));
|
||||
}
|
||||
|
||||
void InputState::HideCursor()
|
||||
{
|
||||
MouseX = INT32_MIN;
|
||||
MouseY = INT32_MIN;
|
||||
MouseDeltaX = 0;
|
||||
MouseDeltaY = 0;
|
||||
}
|
||||
|
||||
void InputState::SetBit(uint32_t bit, bool value, InputBufferType inputType)
|
||||
{
|
||||
uint8_t* data = GetInputBuffer(inputType);
|
||||
|
||||
if (data == nullptr || bit < 0 || bit >= MAX_BUTTON_BIT)
|
||||
return;
|
||||
|
||||
int byteIndex = (bit / 8);
|
||||
int bitIndex = (bit % 8);
|
||||
|
||||
BYTE mask = (1 << bitIndex);
|
||||
|
||||
data[byteIndex] = value ? (data[byteIndex] | mask) : (data[byteIndex] & ~mask);
|
||||
}
|
||||
|
||||
uint8_t* InputState::GetInputBuffer(InputBufferType inputType)
|
||||
{
|
||||
switch (inputType)
|
||||
{
|
||||
case InputBufferType_Tapped:
|
||||
return (uint8_t*)&Tapped;
|
||||
|
||||
case InputBufferType_Released:
|
||||
return (uint8_t*)&Released;
|
||||
|
||||
case InputBufferType_Down:
|
||||
return (uint8_t*)&Down;
|
||||
|
||||
case InputBufferType_DoubleTapped:
|
||||
return (uint8_t*)&DoubleTapped;
|
||||
|
||||
case InputBufferType_IntervalTapped:
|
||||
return (uint8_t*)&IntervalTapped;
|
||||
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
#include "JvsButtons.h"
|
||||
#include "InputBufferType.h"
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
const int MAX_BUTTON_BIT = 0x6F;
|
||||
|
||||
// The button state is larger than the size of a register
|
||||
// but only the first 32 bits are used during normal gameplay
|
||||
// so this will provide the convenience of still being able to access them through a bit field
|
||||
union ButtonState
|
||||
{
|
||||
JvsButtons Buttons;
|
||||
uint32_t State[4];
|
||||
};
|
||||
|
||||
// total sizeof() == 0x20E0
|
||||
struct InputState
|
||||
{
|
||||
ButtonState Tapped;
|
||||
ButtonState Released;
|
||||
|
||||
ButtonState Down;
|
||||
uint32_t Padding_20[4];
|
||||
|
||||
ButtonState DoubleTapped;
|
||||
uint32_t Padding_30[4];
|
||||
|
||||
ButtonState IntervalTapped;
|
||||
uint32_t Padding_38[12];
|
||||
|
||||
int32_t MouseX;
|
||||
int32_t MouseY;
|
||||
int32_t MouseDeltaX;
|
||||
int32_t MouseDeltaY;
|
||||
|
||||
uint32_t Padding_AC[8];
|
||||
uint8_t Padding_D0[3];
|
||||
char Key;
|
||||
|
||||
void ClearState();
|
||||
void HideCursor();
|
||||
void SetBit(uint32_t bit, bool value, InputBufferType inputType);
|
||||
uint8_t* GetInputBuffer(InputBufferType inputType);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
enum JvsButtons : uint32_t
|
||||
{
|
||||
JVS_NONE = 0 << 0x00, // 0x0
|
||||
|
||||
JVS_TEST = 1 << 0x00, // 0x1
|
||||
JVS_SERVICE = 1 << 0x01, // 0x2
|
||||
|
||||
JVS_START = 1 << 0x02, // 0x4
|
||||
JVS_TRIANGLE = 1 << 0x07, // 0x80
|
||||
JVS_SQUARE = 1 << 0x08, // 0x100
|
||||
JVS_CROSS = 1 << 0x09, // 0x200
|
||||
JVS_CIRCLE = 1 << 0x0A, // 0x400
|
||||
JVS_L = 1 << 0x0B, // 0x800
|
||||
JVS_R = 1 << 0x0C, // 0x1000
|
||||
|
||||
JVS_SW1 = 1 << 0x12, // 0x40000
|
||||
JVS_SW2 = 1 << 0x13, // 0x80000
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
#include "TouchPanelEmulator.h"
|
||||
#include <iostream>
|
||||
#include "../ComponentsManager.h"
|
||||
#include "../../Constants.h"
|
||||
#include "../../Input/Mouse/Mouse.h"
|
||||
#include "../../Input/Keyboard/Keyboard.h"
|
||||
|
||||
using namespace TLAC::Input;
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
TouchPanelEmulator::TouchPanelEmulator()
|
||||
{
|
||||
}
|
||||
|
||||
TouchPanelEmulator::~TouchPanelEmulator()
|
||||
{
|
||||
}
|
||||
|
||||
const char* TouchPanelEmulator::GetDisplayName()
|
||||
{
|
||||
return "touch_panel_emulator";
|
||||
}
|
||||
|
||||
void TouchPanelEmulator::Initialize(ComponentsManager* manager)
|
||||
{
|
||||
componentsManager = manager;
|
||||
state = GetTouchStatePtr((void*)TASK_TOUCH_ADDRESS);
|
||||
}
|
||||
|
||||
void TouchPanelEmulator::Update()
|
||||
{
|
||||
state->ConnectionState = 1;
|
||||
}
|
||||
|
||||
void TouchPanelEmulator::UpdateInput()
|
||||
{
|
||||
if (!componentsManager->GetUpdateGameInput() || componentsManager->IsDwGuiActive() || componentsManager->IsDwGuiHovered())
|
||||
return;
|
||||
|
||||
// TODO: rescale TouchReaction aet position
|
||||
auto keyboard = Keyboard::GetInstance();
|
||||
auto pos = Mouse::GetInstance()->GetRelativePosition();
|
||||
|
||||
state->XPosition = (float)pos.x;
|
||||
state->YPosition = (float)pos.y;
|
||||
|
||||
bool down = keyboard->IsDown(VK_LBUTTON);
|
||||
bool released = keyboard->IsReleased(VK_LBUTTON);
|
||||
|
||||
state->ContactType = (down ? 0x2 : released ? 0x1 : 0x0);
|
||||
state->Pressure = (float)(state->ContactType != 0);
|
||||
}
|
||||
|
||||
TouchPanelState* TouchPanelEmulator::GetTouchStatePtr(void *address)
|
||||
{
|
||||
return (TouchPanelState*)address;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
#include "../EmulatorComponent.h"
|
||||
#include "TouchPanelState.h"
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
class TouchPanelEmulator : public EmulatorComponent
|
||||
{
|
||||
public:
|
||||
TouchPanelEmulator();
|
||||
~TouchPanelEmulator();
|
||||
|
||||
virtual const char* GetDisplayName() override;
|
||||
|
||||
virtual void Initialize(ComponentsManager*) override;
|
||||
virtual void Update() override;
|
||||
virtual void UpdateInput() override;
|
||||
|
||||
private:
|
||||
ComponentsManager* componentsManager;
|
||||
|
||||
TouchPanelState* state;
|
||||
TouchPanelState* GetTouchStatePtr(void *address);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
struct TouchPanelState
|
||||
{
|
||||
int Padding00[0x1E];
|
||||
int ConnectionState;
|
||||
int Padding01[0x06];
|
||||
float XPosition;
|
||||
float YPosition;
|
||||
float Pressure;
|
||||
int ContactType;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
#include "TouchSliderEmulator.h"
|
||||
#include "../ComponentsManager.h"
|
||||
#include "../../Constants.h"
|
||||
#include "../../framework.h"
|
||||
#include "../../Input/Mouse/Mouse.h"
|
||||
#include "../../Input/Keyboard/Keyboard.h"
|
||||
#include "../../Input/Bindings/KeyboardBinding.h"
|
||||
#include "../../Input/KeyConfig/Config.h"
|
||||
#include "../../FileSystem/ConfigFile.h"
|
||||
#include "../../Utilities/Math.h"
|
||||
#include <algorithm>
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace TLAC::Input;
|
||||
using namespace TLAC::Input::KeyConfig;
|
||||
using namespace TLAC::Utilities;
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
const std::string KEY_CONFIG_FILE_NAME = "keyconfig.ini";
|
||||
|
||||
TouchSliderEmulator::TouchSliderEmulator()
|
||||
{
|
||||
}
|
||||
|
||||
TouchSliderEmulator::~TouchSliderEmulator()
|
||||
{
|
||||
delete LeftSideSlideLeft;
|
||||
delete LeftSideSlideRight;
|
||||
|
||||
delete RightSideSlideLeft;
|
||||
delete RightSideSlideRight;
|
||||
}
|
||||
|
||||
const char* TouchSliderEmulator::GetDisplayName()
|
||||
{
|
||||
return "touch_slider_emulator";
|
||||
}
|
||||
|
||||
void TouchSliderEmulator::Initialize(ComponentsManager* manager)
|
||||
{
|
||||
componentsManager = manager;
|
||||
sliderState = (TouchSliderState*)SLIDER_CTRL_TASK_ADDRESS;
|
||||
|
||||
LeftSideSlideLeft = new Binding();
|
||||
LeftSideSlideRight = new Binding();
|
||||
|
||||
RightSideSlideLeft = new Binding();
|
||||
RightSideSlideRight = new Binding();
|
||||
|
||||
FileSystem::ConfigFile configFile(framework::GetModuleDirectory(), KEY_CONFIG_FILE_NAME);
|
||||
configFile.OpenRead();
|
||||
|
||||
Config::BindConfigKeys(configFile.ConfigMap, "LEFT_SIDE_SLIDE_LEFT", *LeftSideSlideLeft, { "Q" });
|
||||
Config::BindConfigKeys(configFile.ConfigMap, "LEFT_SIDE_SLIDE_RIGHT", *LeftSideSlideRight, { "E" });
|
||||
|
||||
Config::BindConfigKeys(configFile.ConfigMap, "RIGHT_SIDE_SLIDE_LEFT", *RightSideSlideLeft, { "U" });
|
||||
Config::BindConfigKeys(configFile.ConfigMap, "RIGHT_SIDE_SLIDE_RIGHT", *RightSideSlideRight, { "O" });
|
||||
|
||||
float touchSliderEmulationSpeed = configFile.GetFloatValue("touch_slider_emulation_speed");
|
||||
|
||||
if (touchSliderEmulationSpeed != 0.0f)
|
||||
sliderSpeed = touchSliderEmulationSpeed;
|
||||
}
|
||||
|
||||
void TouchSliderEmulator::Update()
|
||||
{
|
||||
sliderState->State = SLIDER_OK;
|
||||
}
|
||||
|
||||
void TouchSliderEmulator::UpdateInput()
|
||||
{
|
||||
if (!componentsManager->GetUpdateGameInput() || componentsManager->IsDwGuiActive())
|
||||
return;
|
||||
|
||||
sliderIncrement = GetElapsedTime() / sliderSpeed;
|
||||
|
||||
constexpr float sensorStep = (1.0f / SLIDER_SENSORS);
|
||||
|
||||
EmulateSliderInput(LeftSideSlideLeft, LeftSideSlideRight, ContactPoints[0], 0.0f, 0.5f);
|
||||
EmulateSliderInput(RightSideSlideLeft, RightSideSlideRight, ContactPoints[1], 0.5f + sensorStep, 1.0f + sensorStep);
|
||||
|
||||
sliderState->ResetSensors();
|
||||
|
||||
for (int i = 0; i < CONTACT_POINTS; i++)
|
||||
ApplyContactPoint(ContactPoints[i], i);
|
||||
}
|
||||
|
||||
void TouchSliderEmulator::OnFocusLost()
|
||||
{
|
||||
sliderState->ResetSensors();
|
||||
}
|
||||
|
||||
void TouchSliderEmulator::EmulateSliderInput(Binding *leftBinding, Binding *rightBinding, ContactPoint &contactPoint, float start, float end)
|
||||
{
|
||||
bool leftDown = leftBinding->AnyDown();
|
||||
bool rightDown = rightBinding->AnyDown();
|
||||
|
||||
if (leftDown)
|
||||
contactPoint.Position -= sliderIncrement;
|
||||
else if (rightDown)
|
||||
contactPoint.Position += sliderIncrement;
|
||||
|
||||
if (contactPoint.Position < start)
|
||||
contactPoint.Position = end;
|
||||
|
||||
if (contactPoint.Position > end)
|
||||
contactPoint.Position = start;
|
||||
|
||||
bool leftTapped = leftBinding->AnyTapped();
|
||||
bool rightTapped = rightBinding->AnyTapped();
|
||||
|
||||
if (leftTapped || rightTapped)
|
||||
contactPoint.Position = (start + end) / 2.0f;
|
||||
|
||||
contactPoint.InContact = leftDown || rightDown;
|
||||
}
|
||||
|
||||
void TouchSliderEmulator::ApplyContactPoint(ContactPoint &contactPoint, int section)
|
||||
{
|
||||
sliderState->SectionTouched[section] = contactPoint.InContact;
|
||||
|
||||
int pressure = contactPoint.InContact ? FULL_PRESSURE : NO_PRESSURE;
|
||||
float position = std::clamp(contactPoint.Position, 0.0f, 1.0f);
|
||||
|
||||
if (contactPoint.InContact)
|
||||
{
|
||||
int sensor = (int)(position * (SLIDER_SENSORS - 1));
|
||||
|
||||
sliderState->SetSensor(sensor, pressure);
|
||||
}
|
||||
|
||||
constexpr float startRange = -1.0f;
|
||||
constexpr float endRange = +1.0f;
|
||||
|
||||
sliderState->SectionPositions[section] = contactPoint.InContact ? (ConvertRange(0.0f, 1.0f, startRange, endRange, position)) : 0.0f;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
#include "../EmulatorComponent.h"
|
||||
#include "TouchSliderState.h"
|
||||
#include "../../Input/Bindings/Binding.h"
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
constexpr int SLIDER_INPUTS = 4;
|
||||
constexpr int CONTACT_POINTS = 2;
|
||||
|
||||
struct ContactPoint
|
||||
{
|
||||
float Position;
|
||||
bool InContact;
|
||||
};
|
||||
|
||||
class TouchSliderEmulator : public EmulatorComponent
|
||||
{
|
||||
public:
|
||||
Input::Binding* LeftSideSlideLeft;
|
||||
Input::Binding* LeftSideSlideRight;
|
||||
|
||||
Input::Binding* RightSideSlideLeft;
|
||||
Input::Binding* RightSideSlideRight;
|
||||
|
||||
TouchSliderEmulator();
|
||||
~TouchSliderEmulator();
|
||||
|
||||
virtual const char* GetDisplayName() override;
|
||||
|
||||
virtual void Initialize(ComponentsManager*) override;
|
||||
virtual void Update() override;
|
||||
virtual void UpdateInput() override;
|
||||
|
||||
virtual void OnFocusLost() override;
|
||||
|
||||
private:
|
||||
ComponentsManager* componentsManager;
|
||||
float sliderSpeed = 750.0f;
|
||||
float sliderIncrement;
|
||||
|
||||
TouchSliderState *sliderState;
|
||||
ContactPoint ContactPoints[CONTACT_POINTS];
|
||||
|
||||
void EmulateSliderInput(Input::Binding *leftBinding, Input::Binding *rightBinding, ContactPoint &contactPoint, float start, float end);
|
||||
void ApplyContactPoint(ContactPoint &contactPoint, int section);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#include "TouchSliderState.h"
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
void TouchSliderState::SetSensor(int index, int value)
|
||||
{
|
||||
if (index < 0 || index >= SLIDER_SENSORS)
|
||||
return;
|
||||
|
||||
SensorPressureLevels[index] = value;
|
||||
SensorTouched[index].IsTouched = value > 0;
|
||||
}
|
||||
|
||||
void TouchSliderState::ResetSensors()
|
||||
{
|
||||
for (int i = 0; i < SLIDER_SENSORS; i++)
|
||||
SetSensor(i, NO_PRESSURE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
#define SLIDER_OK 3
|
||||
#define SLIDER_SECTIONS 4
|
||||
#define SLIDER_SENSORS 32
|
||||
|
||||
#define NO_PRESSURE 0
|
||||
#define FULL_PRESSURE 180
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
struct TouchSliderState
|
||||
{
|
||||
uint8_t Padding0000[112];
|
||||
|
||||
int32_t State;
|
||||
|
||||
uint8_t Padding0074[20 + 12];
|
||||
|
||||
int32_t SensorPressureLevels[SLIDER_SENSORS];
|
||||
|
||||
uint8_t Padding0108[52 - 12];
|
||||
|
||||
float SectionPositions[SLIDER_SECTIONS];
|
||||
int SectionConnections[SLIDER_SECTIONS];
|
||||
uint8_t Padding015C[4];
|
||||
bool SectionTouched[SLIDER_SECTIONS];
|
||||
|
||||
uint8_t Padding013C[3128 - 52 - 40];
|
||||
|
||||
struct
|
||||
{
|
||||
uint8_t Padding00[2];
|
||||
bool IsTouched;
|
||||
uint8_t Padding[45];
|
||||
} SensorTouched[SLIDER_SENSORS];
|
||||
|
||||
void SetSensor(int index, int value);
|
||||
void ResetSensors();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,973 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
struct PlayerData
|
||||
{
|
||||
int8_t use_card;
|
||||
int8_t freeplay;
|
||||
int8_t field_2;
|
||||
int8_t field_3;
|
||||
int32_t card_type;
|
||||
int32_t field_8;
|
||||
int32_t field_C;
|
||||
int32_t field_10;
|
||||
int32_t field_14;
|
||||
int32_t field_18;
|
||||
int32_t field_1C;
|
||||
int32_t field_20;
|
||||
int32_t field_24;
|
||||
int32_t field_28;
|
||||
int32_t field_2C;
|
||||
int32_t field_30;
|
||||
int32_t field_34;
|
||||
int32_t field_38;
|
||||
int32_t field_3C;
|
||||
int32_t field_40;
|
||||
int32_t field_44;
|
||||
int32_t field_48;
|
||||
int32_t field_4C;
|
||||
int32_t field_50;
|
||||
int32_t field_54;
|
||||
int32_t field_58;
|
||||
int32_t field_5C;
|
||||
int32_t field_60;
|
||||
int32_t field_64;
|
||||
int32_t field_68;
|
||||
int32_t field_6C;
|
||||
int32_t field_70;
|
||||
int32_t field_74;
|
||||
int32_t field_78;
|
||||
int32_t field_7C;
|
||||
int32_t field_80;
|
||||
int32_t field_84;
|
||||
int32_t field_88;
|
||||
int32_t field_8C;
|
||||
int32_t field_90;
|
||||
int32_t field_94;
|
||||
int32_t field_98;
|
||||
int32_t field_9C;
|
||||
int32_t field_A0;
|
||||
int32_t field_A4;
|
||||
int32_t field_A8;
|
||||
int32_t field_AC;
|
||||
int32_t field_B0;
|
||||
int32_t field_B4;
|
||||
int32_t field_B8;
|
||||
int32_t field_BC;
|
||||
int32_t field_C0;
|
||||
int32_t field_C4;
|
||||
int32_t field_C8;
|
||||
int32_t field_CC;
|
||||
int32_t play_data_id;
|
||||
int32_t accept_index;
|
||||
int32_t start_index;
|
||||
int32_t field_DC;
|
||||
char* player_name;
|
||||
int32_t field_E8;
|
||||
int32_t field_EC;
|
||||
int32_t field_F0;
|
||||
int32_t field_F4;
|
||||
int32_t field_F8;
|
||||
int32_t field_FC;
|
||||
char* level_name;
|
||||
int32_t field_108;
|
||||
int32_t field_10C;
|
||||
int32_t field_110;
|
||||
int32_t field_114;
|
||||
int32_t field_118;
|
||||
int32_t field_11C;
|
||||
int32_t field_120;
|
||||
int32_t level_plate_id;
|
||||
int32_t field_128;
|
||||
int32_t vocaloid_point;
|
||||
int32_t hp_vol;
|
||||
int32_t act_toggle;
|
||||
int32_t act_vol;
|
||||
int32_t act_slide_vol;
|
||||
int32_t field_140;
|
||||
int32_t field_144;
|
||||
int32_t field_148;
|
||||
int32_t field_14C;
|
||||
int32_t field_150;
|
||||
int32_t field_154;
|
||||
int32_t field_158;
|
||||
int32_t field_15C;
|
||||
int32_t field_160;
|
||||
int32_t field_164;
|
||||
int32_t field_168;
|
||||
int32_t field_16C;
|
||||
int32_t field_170;
|
||||
int32_t field_174;
|
||||
int32_t field_178;
|
||||
int32_t field_17C;
|
||||
int32_t field_180;
|
||||
int32_t field_184;
|
||||
int32_t field_188;
|
||||
int32_t field_18C;
|
||||
int32_t field_190;
|
||||
int32_t field_194;
|
||||
int32_t field_198;
|
||||
int32_t field_19C;
|
||||
int32_t field_1A0;
|
||||
int32_t field_1A4;
|
||||
int32_t field_1A8;
|
||||
int32_t field_1AC;
|
||||
int32_t field_1B0;
|
||||
int32_t field_1B4;
|
||||
int32_t field_1B8;
|
||||
int32_t field_1BC;
|
||||
int32_t field_1C0;
|
||||
int32_t field_1C4;
|
||||
int32_t field_1C8;
|
||||
int32_t field_1CC;
|
||||
int32_t field_1D0;
|
||||
int32_t field_1D4;
|
||||
int32_t field_1D8;
|
||||
int32_t field_1DC;
|
||||
int32_t field_1E0;
|
||||
int32_t field_1E4;
|
||||
int32_t field_1E8;
|
||||
int32_t field_1EC;
|
||||
int32_t field_1F0;
|
||||
int32_t field_1F4;
|
||||
int32_t field_1F8;
|
||||
int32_t field_1FC;
|
||||
int32_t field_200;
|
||||
int32_t field_204;
|
||||
int32_t field_208;
|
||||
int32_t field_20C;
|
||||
int32_t field_210;
|
||||
int32_t field_214;
|
||||
int32_t field_218;
|
||||
int32_t field_21C;
|
||||
int32_t field_220;
|
||||
int32_t field_224;
|
||||
int32_t field_228;
|
||||
int32_t field_22C;
|
||||
int32_t field_230;
|
||||
int32_t field_234;
|
||||
int32_t field_238;
|
||||
int32_t field_23C;
|
||||
int32_t field_240;
|
||||
int32_t field_244;
|
||||
int32_t field_248;
|
||||
int32_t field_24C;
|
||||
int32_t field_250;
|
||||
int32_t field_254;
|
||||
int32_t field_258;
|
||||
int32_t field_25C;
|
||||
int32_t field_260;
|
||||
int32_t field_264;
|
||||
int32_t field_268;
|
||||
int32_t field_26C;
|
||||
int32_t field_270;
|
||||
int32_t field_274;
|
||||
int32_t field_278;
|
||||
int32_t field_27C;
|
||||
int32_t field_280;
|
||||
int32_t field_284;
|
||||
int32_t field_288;
|
||||
int32_t field_28C;
|
||||
int32_t field_290;
|
||||
int32_t field_294;
|
||||
int32_t field_298;
|
||||
int32_t field_29C;
|
||||
int32_t field_2A0;
|
||||
int32_t field_2A4;
|
||||
int32_t field_2A8;
|
||||
int32_t field_2AC;
|
||||
int8_t use_pv_module_equip;
|
||||
int8_t ch_pv_module_equip;
|
||||
int8_t field_2B2;
|
||||
int8_t field_2B3;
|
||||
int32_t module_filter_kind;
|
||||
int32_t field_2B8;
|
||||
int32_t field_2BC;
|
||||
int32_t field_2C0;
|
||||
int32_t field_2C4;
|
||||
int32_t field_2C8;
|
||||
int32_t field_2CC;
|
||||
int32_t field_2D0;
|
||||
int32_t field_2D4;
|
||||
int32_t field_2D8;
|
||||
int32_t field_2DC;
|
||||
int32_t field_2E0;
|
||||
int32_t field_2E4;
|
||||
int32_t field_2E8;
|
||||
int32_t field_2EC;
|
||||
int32_t field_2F0;
|
||||
int32_t field_2F4;
|
||||
int32_t field_2F8;
|
||||
int32_t field_2FC;
|
||||
int32_t field_300;
|
||||
int32_t field_304;
|
||||
int32_t field_308;
|
||||
int32_t field_30C;
|
||||
int32_t field_310;
|
||||
int32_t field_314;
|
||||
int32_t field_318;
|
||||
int32_t field_31C;
|
||||
int32_t field_320;
|
||||
int32_t field_324;
|
||||
int32_t field_328;
|
||||
int32_t field_32C;
|
||||
int32_t field_330;
|
||||
int32_t field_334;
|
||||
int32_t field_338;
|
||||
int32_t field_33C;
|
||||
int32_t field_340;
|
||||
int32_t field_344;
|
||||
int32_t field_348;
|
||||
int32_t field_34C;
|
||||
int32_t field_350;
|
||||
int32_t field_354;
|
||||
int32_t field_358;
|
||||
int32_t field_35C;
|
||||
int32_t field_360;
|
||||
int32_t field_364;
|
||||
int32_t field_368;
|
||||
int32_t field_36C;
|
||||
int32_t field_370;
|
||||
int32_t field_374;
|
||||
int32_t field_378;
|
||||
int32_t field_37C;
|
||||
int32_t field_380;
|
||||
int32_t field_384;
|
||||
int32_t field_388;
|
||||
int32_t field_38C;
|
||||
int32_t field_390;
|
||||
int32_t field_394;
|
||||
int32_t field_398;
|
||||
int32_t field_39C;
|
||||
int32_t field_3A0;
|
||||
int32_t field_3A4;
|
||||
int32_t field_3A8;
|
||||
int32_t field_3AC;
|
||||
int32_t field_3B0;
|
||||
int32_t field_3B4;
|
||||
int32_t field_3B8;
|
||||
int32_t field_3BC;
|
||||
int32_t field_3C0;
|
||||
int32_t field_3C4;
|
||||
int32_t field_3C8;
|
||||
int32_t field_3CC;
|
||||
int32_t field_3D0;
|
||||
int32_t field_3D4;
|
||||
int32_t field_3D8;
|
||||
int32_t field_3DC;
|
||||
int32_t field_3E0;
|
||||
int32_t field_3E4;
|
||||
int32_t field_3E8;
|
||||
int32_t field_3EC;
|
||||
int32_t field_3F0;
|
||||
int32_t field_3F4;
|
||||
int32_t field_3F8;
|
||||
int32_t field_3FC;
|
||||
int32_t field_400;
|
||||
int32_t field_404;
|
||||
int32_t field_408;
|
||||
int32_t field_40C;
|
||||
int32_t field_410;
|
||||
int32_t field_414;
|
||||
int32_t field_418;
|
||||
int32_t field_41C;
|
||||
int32_t field_420;
|
||||
int32_t field_424;
|
||||
int32_t field_428;
|
||||
int32_t field_42C;
|
||||
int32_t field_430;
|
||||
int32_t field_434;
|
||||
int32_t field_438;
|
||||
int32_t field_43C;
|
||||
int32_t field_440;
|
||||
int32_t field_444;
|
||||
int32_t field_448;
|
||||
int32_t field_44C;
|
||||
int32_t field_450;
|
||||
int32_t field_454;
|
||||
int32_t field_458;
|
||||
int32_t field_45C;
|
||||
int32_t field_460;
|
||||
int32_t field_464;
|
||||
int32_t field_468;
|
||||
int32_t field_46C;
|
||||
int32_t field_470;
|
||||
int32_t field_474;
|
||||
int32_t field_478;
|
||||
int32_t field_47C;
|
||||
int32_t field_480;
|
||||
int32_t field_484;
|
||||
int32_t field_488;
|
||||
int32_t field_48C;
|
||||
int32_t field_490;
|
||||
int32_t field_494;
|
||||
int32_t field_498;
|
||||
int32_t field_49C;
|
||||
int32_t field_4A0;
|
||||
int32_t field_4A4;
|
||||
int32_t field_4A8;
|
||||
int32_t field_4AC;
|
||||
int32_t field_4B0;
|
||||
int32_t field_4B4;
|
||||
int32_t field_4B8;
|
||||
int32_t field_4BC;
|
||||
int32_t field_4C0;
|
||||
int32_t field_4C4;
|
||||
int32_t field_4C8;
|
||||
int32_t field_4CC;
|
||||
int32_t field_4D0;
|
||||
int32_t field_4D4;
|
||||
int32_t field_4D8;
|
||||
int32_t field_4DC;
|
||||
int32_t field_4E0;
|
||||
int32_t field_4E4;
|
||||
int32_t field_4E8;
|
||||
int32_t field_4EC;
|
||||
int32_t field_4F0;
|
||||
int32_t field_4F4;
|
||||
int32_t field_4F8;
|
||||
int32_t field_4FC;
|
||||
int32_t field_500;
|
||||
int32_t field_504;
|
||||
int32_t field_508;
|
||||
int32_t field_50C;
|
||||
int32_t field_510;
|
||||
int32_t field_514;
|
||||
int32_t field_518;
|
||||
int32_t field_51C;
|
||||
int32_t field_520;
|
||||
int32_t field_524;
|
||||
int32_t field_528;
|
||||
int32_t field_52C;
|
||||
int32_t field_530;
|
||||
int32_t field_534;
|
||||
int32_t field_538;
|
||||
int32_t field_53C;
|
||||
int32_t field_540;
|
||||
int32_t field_544;
|
||||
int32_t skin_equip;
|
||||
int32_t skin_equip_cmn;
|
||||
int32_t use_pv_skin_equip;
|
||||
int32_t btn_se_equip;
|
||||
int32_t btn_se_equip_cmn;
|
||||
int32_t use_pv_btn_se_equip;
|
||||
int32_t slide_se_equip;
|
||||
int32_t slide_se_equip_cmn;
|
||||
int32_t use_pv_slide_se_equip;
|
||||
int32_t chainslide_se_equip;
|
||||
int32_t chainslide_se_equip_cmn;
|
||||
int32_t use_pv_chainslide_se_equip;
|
||||
int32_t slidertouch_se_equip;
|
||||
int32_t slidertouch_se_equip_cmn;
|
||||
int32_t use_pv_slidertouch_se_equip;
|
||||
int32_t field_584;
|
||||
int32_t field_588;
|
||||
int32_t field_58C;
|
||||
int32_t field_590;
|
||||
int32_t field_594;
|
||||
int32_t field_598;
|
||||
int32_t field_59C;
|
||||
int32_t field_5A0;
|
||||
int32_t field_5A4;
|
||||
int32_t field_5A8;
|
||||
int32_t field_5AC;
|
||||
int32_t field_5B0;
|
||||
int32_t field_5B4;
|
||||
int32_t field_5B8;
|
||||
int32_t field_5BC;
|
||||
int32_t field_5C0;
|
||||
int32_t field_5C4;
|
||||
int32_t field_5C8;
|
||||
int32_t field_5CC;
|
||||
int32_t field_5D0;
|
||||
int32_t field_5D4;
|
||||
int32_t field_5D8;
|
||||
int32_t field_5DC;
|
||||
int32_t field_5E0;
|
||||
int32_t field_5E4;
|
||||
int32_t field_5E8;
|
||||
int32_t field_5EC;
|
||||
int32_t field_5F0;
|
||||
int32_t field_5F4;
|
||||
int32_t field_5F8;
|
||||
int32_t field_5FC;
|
||||
int32_t field_600;
|
||||
int32_t field_604;
|
||||
int32_t field_608;
|
||||
int32_t field_60C;
|
||||
int32_t field_610;
|
||||
int32_t field_614;
|
||||
int32_t field_618;
|
||||
int32_t field_61C;
|
||||
int32_t field_620;
|
||||
int32_t field_624;
|
||||
int32_t field_628;
|
||||
int32_t field_62C;
|
||||
int32_t field_630;
|
||||
int32_t field_634;
|
||||
int32_t field_638;
|
||||
int32_t field_63C;
|
||||
int32_t field_640;
|
||||
int32_t field_644;
|
||||
int32_t field_648;
|
||||
int32_t field_64C;
|
||||
int32_t field_650;
|
||||
int32_t field_654;
|
||||
int32_t field_658;
|
||||
int32_t field_65C;
|
||||
int32_t field_660;
|
||||
int32_t field_664;
|
||||
int32_t field_668;
|
||||
int32_t field_66C;
|
||||
int32_t field_670;
|
||||
int32_t field_674;
|
||||
int32_t field_678;
|
||||
int32_t field_67C;
|
||||
int32_t field_680;
|
||||
int32_t field_684;
|
||||
int32_t field_688;
|
||||
int32_t field_68C;
|
||||
int32_t field_690;
|
||||
int32_t field_694;
|
||||
int32_t field_698;
|
||||
int32_t field_69C;
|
||||
int32_t field_6A0;
|
||||
int32_t field_6A4;
|
||||
int32_t field_6A8;
|
||||
int32_t field_6AC;
|
||||
int32_t field_6B0;
|
||||
int32_t field_6B4;
|
||||
int32_t field_6B8;
|
||||
int32_t field_6BC;
|
||||
int32_t field_6C0;
|
||||
int32_t field_6C4;
|
||||
int32_t field_6C8;
|
||||
int32_t field_6CC;
|
||||
int32_t field_6D0;
|
||||
int32_t field_6D4;
|
||||
int32_t field_6D8;
|
||||
int32_t field_6DC;
|
||||
int32_t field_6E0;
|
||||
int32_t field_6E4;
|
||||
int32_t field_6E8;
|
||||
int32_t field_6EC;
|
||||
int32_t field_6F0;
|
||||
int32_t field_6F4;
|
||||
int32_t field_6F8;
|
||||
int32_t field_6FC;
|
||||
int32_t field_700;
|
||||
int32_t field_704;
|
||||
int32_t field_708;
|
||||
int32_t field_70C;
|
||||
int32_t field_710;
|
||||
int32_t field_714;
|
||||
int32_t field_718;
|
||||
int32_t field_71C;
|
||||
int32_t field_720;
|
||||
int32_t field_724;
|
||||
int32_t field_728;
|
||||
int32_t field_72C;
|
||||
int32_t field_730;
|
||||
int32_t field_734;
|
||||
int32_t field_738;
|
||||
int32_t field_73C;
|
||||
int32_t field_740;
|
||||
int32_t field_744;
|
||||
int32_t field_748;
|
||||
int32_t field_74C;
|
||||
int32_t field_750;
|
||||
int32_t field_754;
|
||||
int32_t field_758;
|
||||
int32_t field_75C;
|
||||
int32_t field_760;
|
||||
int32_t field_764;
|
||||
int32_t field_768;
|
||||
int32_t field_76C;
|
||||
int32_t field_770;
|
||||
int32_t field_774;
|
||||
int32_t field_778;
|
||||
int32_t field_77C;
|
||||
int32_t field_780;
|
||||
int32_t field_784;
|
||||
int32_t field_788;
|
||||
int32_t field_78C;
|
||||
int32_t field_790;
|
||||
int32_t field_794;
|
||||
int32_t field_798;
|
||||
int32_t field_79C;
|
||||
int32_t field_7A0;
|
||||
int32_t field_7A4;
|
||||
int32_t field_7A8;
|
||||
int32_t field_7AC;
|
||||
int32_t field_7B0;
|
||||
int32_t field_7B4;
|
||||
int32_t field_7B8;
|
||||
int32_t field_7BC;
|
||||
int32_t field_7C0;
|
||||
int32_t field_7C4;
|
||||
int32_t field_7C8;
|
||||
int32_t field_7CC;
|
||||
int32_t field_7D0;
|
||||
int32_t field_7D4;
|
||||
int32_t field_7D8;
|
||||
int32_t field_7DC;
|
||||
int32_t field_7E0;
|
||||
int32_t field_7E4;
|
||||
int32_t field_7E8;
|
||||
int32_t field_7EC;
|
||||
int32_t field_7F0;
|
||||
int32_t field_7F4;
|
||||
int32_t field_7F8;
|
||||
int32_t field_7FC;
|
||||
int32_t field_800;
|
||||
int32_t field_804;
|
||||
int32_t field_808;
|
||||
int32_t field_80C;
|
||||
int32_t field_810;
|
||||
int32_t field_814;
|
||||
int32_t field_818;
|
||||
int32_t field_81C;
|
||||
int32_t field_820;
|
||||
int32_t field_824;
|
||||
int32_t field_828;
|
||||
int32_t field_82C;
|
||||
int32_t field_830;
|
||||
int32_t field_834;
|
||||
int32_t field_838;
|
||||
int32_t field_83C;
|
||||
int32_t field_840;
|
||||
int32_t field_844;
|
||||
int32_t field_848;
|
||||
int32_t field_84C;
|
||||
int32_t field_850;
|
||||
int32_t field_854;
|
||||
int32_t field_858;
|
||||
int32_t field_85C;
|
||||
int32_t field_860;
|
||||
int32_t field_864;
|
||||
int32_t field_868;
|
||||
int32_t field_86C;
|
||||
int32_t field_870;
|
||||
int32_t field_874;
|
||||
int32_t field_878;
|
||||
int32_t field_87C;
|
||||
int32_t field_880;
|
||||
int32_t field_884;
|
||||
int32_t field_888;
|
||||
int32_t field_88C;
|
||||
int32_t field_890;
|
||||
int32_t field_894;
|
||||
int32_t field_898;
|
||||
int32_t field_89C;
|
||||
int32_t field_8A0;
|
||||
int32_t field_8A4;
|
||||
int32_t field_8A8;
|
||||
int32_t field_8AC;
|
||||
int32_t field_8B0;
|
||||
int32_t field_8B4;
|
||||
int32_t field_8B8;
|
||||
int32_t field_8BC;
|
||||
int32_t field_8C0;
|
||||
int32_t field_8C4;
|
||||
int32_t field_8C8;
|
||||
int32_t field_8CC;
|
||||
int32_t field_8D0;
|
||||
int32_t field_8D4;
|
||||
int32_t field_8D8;
|
||||
int32_t field_8DC;
|
||||
int32_t field_8E0;
|
||||
int32_t field_8E4;
|
||||
int32_t field_8E8;
|
||||
int32_t field_8EC;
|
||||
int32_t field_8F0;
|
||||
int32_t field_8F4;
|
||||
int32_t field_8F8;
|
||||
int32_t field_8FC;
|
||||
int32_t field_900;
|
||||
int32_t field_904;
|
||||
int32_t field_908;
|
||||
int32_t field_90C;
|
||||
int32_t field_910;
|
||||
int32_t field_914;
|
||||
int32_t field_918;
|
||||
int32_t field_91C;
|
||||
int32_t field_920;
|
||||
int32_t field_924;
|
||||
int32_t field_928;
|
||||
int32_t field_92C;
|
||||
int32_t field_930;
|
||||
int32_t field_934;
|
||||
int32_t field_938;
|
||||
int32_t field_93C;
|
||||
int32_t field_940;
|
||||
int32_t field_944;
|
||||
int32_t field_948;
|
||||
int32_t field_94C;
|
||||
int32_t field_950;
|
||||
int32_t field_954;
|
||||
int32_t field_958;
|
||||
int32_t field_95C;
|
||||
int32_t field_960;
|
||||
int32_t field_964;
|
||||
int32_t field_968;
|
||||
int32_t field_96C;
|
||||
int32_t field_970;
|
||||
int32_t field_974;
|
||||
int32_t field_978;
|
||||
int32_t field_97C;
|
||||
int32_t field_980;
|
||||
int32_t field_984;
|
||||
int32_t field_988;
|
||||
int32_t field_98C;
|
||||
int32_t field_990;
|
||||
int32_t field_994;
|
||||
int32_t field_998;
|
||||
int32_t field_99C;
|
||||
int32_t field_9A0;
|
||||
int32_t field_9A4;
|
||||
int32_t field_9A8;
|
||||
int32_t field_9AC;
|
||||
int32_t field_9B0;
|
||||
int32_t field_9B4;
|
||||
int32_t field_9B8;
|
||||
int32_t field_9BC;
|
||||
int32_t field_9C0;
|
||||
int32_t field_9C4;
|
||||
int32_t field_9C8;
|
||||
int32_t field_9CC;
|
||||
int32_t field_9D0;
|
||||
int32_t field_9D4;
|
||||
int32_t field_9D8;
|
||||
int32_t field_9DC;
|
||||
int32_t field_9E0;
|
||||
int32_t field_9E4;
|
||||
int32_t field_9E8;
|
||||
int32_t field_9EC;
|
||||
int32_t field_9F0;
|
||||
int32_t field_9F4;
|
||||
int32_t field_9F8;
|
||||
int32_t field_9FC;
|
||||
int32_t field_A00;
|
||||
int32_t field_A04;
|
||||
int32_t field_A08;
|
||||
int32_t field_A0C;
|
||||
int32_t field_A10;
|
||||
int32_t field_A14;
|
||||
int32_t field_A18;
|
||||
int32_t field_A1C;
|
||||
int32_t field_A20;
|
||||
int32_t field_A24;
|
||||
int32_t field_A28;
|
||||
int32_t field_A2C;
|
||||
int32_t field_A30;
|
||||
int32_t field_A34;
|
||||
int32_t field_A38;
|
||||
int32_t field_A3C;
|
||||
int32_t field_A40;
|
||||
int32_t field_A44;
|
||||
int32_t field_A48;
|
||||
int32_t field_A4C;
|
||||
int32_t field_A50;
|
||||
int32_t field_A54;
|
||||
int32_t field_A58;
|
||||
int32_t field_A5C;
|
||||
int32_t field_A60;
|
||||
int32_t field_A64;
|
||||
int32_t field_A68;
|
||||
int32_t field_A6C;
|
||||
int32_t field_A70;
|
||||
int32_t field_A74;
|
||||
int32_t field_A78;
|
||||
int32_t field_A7C;
|
||||
int32_t field_A80;
|
||||
int32_t field_A84;
|
||||
int32_t field_A88;
|
||||
int32_t field_A8C;
|
||||
int32_t field_A90;
|
||||
int32_t field_A94;
|
||||
int32_t field_A98;
|
||||
int32_t field_A9C;
|
||||
int32_t field_AA0;
|
||||
int32_t field_AA4;
|
||||
int32_t field_AA8;
|
||||
int32_t field_AAC;
|
||||
int32_t field_AB0;
|
||||
int32_t field_AB4;
|
||||
int32_t field_AB8;
|
||||
int32_t field_ABC;
|
||||
int32_t field_AC0;
|
||||
int32_t field_AC4;
|
||||
int32_t field_AC8;
|
||||
int32_t field_ACC;
|
||||
int32_t field_AD0;
|
||||
int32_t field_AD4;
|
||||
int32_t field_AD8;
|
||||
int32_t field_ADC;
|
||||
int32_t field_AE0;
|
||||
int32_t field_AE4;
|
||||
int32_t field_AE8;
|
||||
int32_t field_AEC;
|
||||
int32_t field_AF0;
|
||||
int32_t field_AF4;
|
||||
int32_t field_AF8;
|
||||
int32_t field_AFC;
|
||||
int32_t field_B00;
|
||||
int32_t field_B04;
|
||||
int32_t field_B08;
|
||||
int32_t field_B0C;
|
||||
int32_t field_B10;
|
||||
int32_t field_B14;
|
||||
int32_t field_B18;
|
||||
int32_t field_B1C;
|
||||
int32_t field_B20;
|
||||
int32_t field_B24;
|
||||
int32_t field_B28;
|
||||
int32_t field_B2C;
|
||||
int32_t field_B30;
|
||||
int32_t field_B34;
|
||||
int32_t field_B38;
|
||||
int32_t field_B3C;
|
||||
int32_t field_B40;
|
||||
int32_t field_B44;
|
||||
int32_t field_B48;
|
||||
int32_t field_B4C;
|
||||
int32_t field_B50;
|
||||
int32_t field_B54;
|
||||
int32_t field_B58;
|
||||
int32_t field_B5C;
|
||||
int32_t field_B60;
|
||||
int32_t field_B64;
|
||||
int32_t field_B68;
|
||||
int32_t field_B6C;
|
||||
int32_t field_B70;
|
||||
int32_t field_B74;
|
||||
int32_t field_B78;
|
||||
int32_t field_B7C;
|
||||
int32_t field_B80;
|
||||
int32_t field_B84;
|
||||
int32_t field_B88;
|
||||
int32_t field_B8C;
|
||||
int32_t field_B90;
|
||||
int32_t field_B94;
|
||||
int32_t field_B98;
|
||||
int32_t field_B9C;
|
||||
int32_t field_BA0;
|
||||
int32_t field_BA4;
|
||||
int32_t field_BA8;
|
||||
int32_t field_BAC;
|
||||
int32_t field_BB0;
|
||||
int32_t field_BB4;
|
||||
int32_t field_BB8;
|
||||
int32_t field_BBC;
|
||||
int32_t field_BC0;
|
||||
int32_t field_BC4;
|
||||
int32_t field_BC8;
|
||||
int32_t field_BCC;
|
||||
int32_t field_BD0;
|
||||
int32_t field_BD4;
|
||||
int32_t field_BD8;
|
||||
int32_t field_BDC;
|
||||
int32_t field_BE0;
|
||||
int32_t field_BE4;
|
||||
int32_t field_BE8;
|
||||
int32_t field_BEC;
|
||||
int32_t field_BF0;
|
||||
int32_t field_BF4;
|
||||
int32_t field_BF8;
|
||||
int32_t field_BFC;
|
||||
int32_t field_C00;
|
||||
int32_t field_C04;
|
||||
int32_t field_C08;
|
||||
int32_t field_C0C;
|
||||
int32_t field_C10;
|
||||
int32_t field_C14;
|
||||
int32_t field_C18;
|
||||
int32_t field_C1C;
|
||||
int32_t field_C20;
|
||||
int32_t field_C24;
|
||||
int32_t field_C28;
|
||||
int32_t field_C2C;
|
||||
int32_t field_C30;
|
||||
int32_t field_C34;
|
||||
int32_t field_C38;
|
||||
int32_t field_C3C;
|
||||
int32_t field_C40;
|
||||
int32_t field_C44;
|
||||
int32_t field_C48;
|
||||
int32_t field_C4C;
|
||||
int32_t field_C50;
|
||||
int32_t field_C54;
|
||||
int32_t field_C58;
|
||||
int32_t field_C5C;
|
||||
int32_t field_C60;
|
||||
int32_t field_C64;
|
||||
int32_t field_C68;
|
||||
int32_t field_C6C;
|
||||
int32_t field_C70;
|
||||
int32_t field_C74;
|
||||
int32_t field_C78;
|
||||
int32_t field_C7C;
|
||||
int32_t field_C80;
|
||||
int32_t field_C84;
|
||||
int32_t field_C88;
|
||||
int32_t field_C8C;
|
||||
int32_t field_C90;
|
||||
int32_t field_C94;
|
||||
int32_t field_C98;
|
||||
int32_t field_C9C;
|
||||
int32_t field_CA0;
|
||||
int32_t field_CA4;
|
||||
int32_t field_CA8;
|
||||
int32_t field_CAC;
|
||||
int32_t field_CB0;
|
||||
int32_t field_CB4;
|
||||
int32_t field_CB8;
|
||||
int32_t field_CBC;
|
||||
int32_t field_CC0;
|
||||
int32_t field_CC4;
|
||||
int32_t field_CC8;
|
||||
int32_t field_CCC;
|
||||
int32_t field_CD0;
|
||||
int32_t field_CD4;
|
||||
int32_t field_CD8;
|
||||
int32_t field_CDC;
|
||||
int32_t field_CE0;
|
||||
int32_t field_CE4;
|
||||
int32_t field_CE8;
|
||||
int32_t field_CEC;
|
||||
int32_t field_CF0;
|
||||
int32_t field_CF4;
|
||||
int32_t field_CF8;
|
||||
int32_t field_CFC;
|
||||
int32_t field_D00;
|
||||
int32_t field_D04;
|
||||
int32_t field_D08;
|
||||
int32_t field_D0C;
|
||||
int32_t field_D10;
|
||||
int32_t field_D14;
|
||||
int32_t field_D18;
|
||||
int32_t field_D1C;
|
||||
int32_t field_D20;
|
||||
int32_t field_D24;
|
||||
int32_t field_D28;
|
||||
int32_t field_D2C;
|
||||
int32_t field_D30;
|
||||
int32_t field_D34;
|
||||
int32_t field_D38;
|
||||
int32_t field_D3C;
|
||||
int32_t field_D40;
|
||||
int32_t field_D44;
|
||||
int32_t field_D48;
|
||||
int32_t field_D4C;
|
||||
int32_t field_D50;
|
||||
int32_t field_D54;
|
||||
int32_t field_D58;
|
||||
int32_t field_D5C;
|
||||
int32_t field_D60;
|
||||
int32_t field_D64;
|
||||
int32_t field_D68;
|
||||
int32_t field_D6C;
|
||||
int32_t field_D70;
|
||||
int32_t field_D74;
|
||||
int32_t field_D78;
|
||||
int32_t field_D7C;
|
||||
int32_t field_D80;
|
||||
int32_t field_D84;
|
||||
int32_t field_D88;
|
||||
int32_t field_D8C;
|
||||
int32_t field_D90;
|
||||
int32_t field_D94;
|
||||
int32_t field_D98;
|
||||
int32_t field_D9C;
|
||||
int32_t field_DA0;
|
||||
int32_t field_DA4;
|
||||
int32_t field_DA8;
|
||||
int32_t field_DAC;
|
||||
int32_t field_DB0;
|
||||
int32_t field_DB4;
|
||||
int32_t field_DB8;
|
||||
int32_t field_DBC;
|
||||
int32_t field_DC0;
|
||||
int32_t field_DC4;
|
||||
int32_t field_DC8;
|
||||
int32_t field_DCC;
|
||||
int32_t field_DD0;
|
||||
int32_t field_DD4;
|
||||
int32_t field_DD8;
|
||||
int32_t field_DDC;
|
||||
int32_t field_DE0;
|
||||
int32_t field_DE4;
|
||||
int32_t field_DE8;
|
||||
int32_t field_DEC;
|
||||
int32_t field_DF0;
|
||||
int32_t field_DF4;
|
||||
int32_t field_DF8;
|
||||
int32_t field_DFC;
|
||||
int32_t field_E00;
|
||||
int32_t field_E04;
|
||||
int32_t field_E08;
|
||||
int32_t field_E0C;
|
||||
int32_t field_E10;
|
||||
int32_t field_E14;
|
||||
int32_t field_E18;
|
||||
int32_t field_E1C;
|
||||
int32_t field_E20;
|
||||
int32_t field_E24;
|
||||
int32_t field_E28;
|
||||
int32_t field_E2C;
|
||||
int32_t field_E30;
|
||||
int8_t field_E34;
|
||||
int8_t game_opts;
|
||||
int8_t field_E36;
|
||||
int8_t field_E37;
|
||||
int32_t field_E38;
|
||||
int32_t field_E3C;
|
||||
int32_t field_E40;
|
||||
int32_t field_E44;
|
||||
int32_t field_E48;
|
||||
int32_t field_E4C;
|
||||
int32_t field_E50;
|
||||
int32_t field_E54;
|
||||
int32_t field_E58;
|
||||
int32_t field_E5C;
|
||||
int32_t field_E60;
|
||||
int32_t field_E64;
|
||||
int32_t field_E68;
|
||||
int32_t field_E6C;
|
||||
int32_t field_E70;
|
||||
int32_t field_E74;
|
||||
int32_t field_E78;
|
||||
int32_t field_E7C;
|
||||
int32_t field_E80;
|
||||
int32_t field_E84;
|
||||
int32_t field_E88;
|
||||
int32_t field_E8C;
|
||||
int32_t field_E90;
|
||||
int32_t field_E94;
|
||||
int32_t field_E98;
|
||||
int32_t field_E9C;
|
||||
int32_t field_EA0;
|
||||
int32_t field_EA4;
|
||||
int32_t field_EA8;
|
||||
int32_t field_EAC;
|
||||
int32_t field_EB0;
|
||||
int32_t field_EB4;
|
||||
int32_t field_EB8;
|
||||
int32_t field_EBC;
|
||||
int32_t field_EC0;
|
||||
int32_t field_EC4;
|
||||
int32_t field_EC8;
|
||||
int32_t field_ECC;
|
||||
int32_t field_ED0;
|
||||
int32_t field_ED4;
|
||||
int32_t field_ED8;
|
||||
int32_t field_EDC;
|
||||
int32_t field_EE0;
|
||||
int32_t field_EE4;
|
||||
int32_t field_EE8;
|
||||
int32_t field_EEC;
|
||||
int32_t field_EF0;
|
||||
int32_t field_EF4;
|
||||
int32_t field_EF8;
|
||||
int32_t field_EFC;
|
||||
};
|
||||
@@ -0,0 +1,342 @@
|
||||
#include "PlayerDataManager.h"
|
||||
#include <string>
|
||||
#include "../framework.h"
|
||||
#include "../Constants.h"
|
||||
#include "../Input/Keyboard/Keyboard.h"
|
||||
#include "../FileSystem/ConfigFile.h"
|
||||
#include "../Constants.h"
|
||||
|
||||
const std::string PLAYER_DATA_FILE_NAME = "playerdata.ini";
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
PlayerDataManager::PlayerDataManager()
|
||||
{
|
||||
}
|
||||
|
||||
PlayerDataManager::~PlayerDataManager()
|
||||
{
|
||||
if (customPlayerData != nullptr)
|
||||
delete customPlayerData;
|
||||
}
|
||||
|
||||
const char* PlayerDataManager::GetDisplayName()
|
||||
{
|
||||
return "player_data_manager";
|
||||
}
|
||||
|
||||
void PlayerDataManager::Initialize(ComponentsManager*)
|
||||
{
|
||||
playerData = (PlayerData*)PLAYER_DATA_ADDRESS;
|
||||
|
||||
ApplyPatch();
|
||||
LoadConfig();
|
||||
ApplyCustomData();
|
||||
}
|
||||
|
||||
void PlayerDataManager::Update()
|
||||
{
|
||||
ApplyCustomData();
|
||||
|
||||
if (false && Input::Keyboard::GetInstance()->IsTapped(VK_F12))
|
||||
{
|
||||
printf("[TLAC] PlayerDataManager::Update(): Loading config...\n");
|
||||
LoadConfig();
|
||||
}
|
||||
if (moduleCardWorkaround) {
|
||||
int* pvId = (int*)0x00000001418054C4;
|
||||
int* modState = (int*)0x00000001411A9790;
|
||||
|
||||
if (!customPlayerData->UseCard)
|
||||
{
|
||||
if (*(char*)0x000000014CC5E270 == 32)
|
||||
{
|
||||
DWORD oldProtect, bck;
|
||||
VirtualProtect((BYTE*)0x00000001405BC8E6, 3, PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
*((BYTE*)0x00000001405BC8E6 + 0) = 0x00;
|
||||
VirtualProtect((BYTE*)0x00000001405BC8E6, 3, oldProtect, &bck);
|
||||
pvModuleLoaded = false;
|
||||
}
|
||||
else {
|
||||
if (!pvModuleLoaded)
|
||||
{
|
||||
pvModuleLoaded = true;
|
||||
DWORD oldProtect, bck;
|
||||
VirtualProtect((BYTE*)0x00000001405BC8E6, 3, PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
*((BYTE*)0x00000001405BC8E6 + 0) = 0x01;
|
||||
VirtualProtect((BYTE*)0x00000001405BC8E6, 3, oldProtect, &bck);
|
||||
}
|
||||
}
|
||||
|
||||
if ((initPvId == false) || ((lastModState == 0) && (*modState == 1)))
|
||||
{
|
||||
if ((lastModState == 0) && (*modState == 1))
|
||||
{
|
||||
*(int*)0x00000001411A8A10 = *(int*)0x00000001411A8A28;
|
||||
*(int*)(0x00000001411A8A10 + 4) = *(int*)(0x00000001411A8A28 + 4);
|
||||
*(int*)(0x00000001411A8A10 + 8) = *(int*)(0x00000001411A8A28 + 8);
|
||||
*(int*)(0x00000001411A8A10 + 12) = *(int*)(0x00000001411A8A28 + 12);
|
||||
*(int*)(0x00000001411A8A10 + 16) = *(int*)(0x00000001411A8A28 + 16);
|
||||
*(int*)(0x00000001411A8A10 + 18) = *(int*)(0x00000001411A8A28 + 18);
|
||||
}
|
||||
|
||||
initPvId = true;
|
||||
lastModState = *modState;
|
||||
DWORD oldProtect, bck;
|
||||
VirtualProtect((BYTE*)0x00000001405CBBA3, 8, PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
*((BYTE*)0x00000001405CBBA3 + 0) = 0x90;
|
||||
*((BYTE*)0x00000001405CBBA3 + 1) = 0x90;
|
||||
*((BYTE*)0x00000001405CBBA3 + 2) = 0x90;
|
||||
*((BYTE*)0x00000001405CBBA3 + 3) = 0x90;
|
||||
*((BYTE*)0x00000001405CBBA3 + 4) = 0x90;
|
||||
*((BYTE*)0x00000001405CBBA3 + 5) = 0x90;
|
||||
*((BYTE*)0x00000001405CBBA3 + 6) = 0x90;
|
||||
*((BYTE*)0x00000001405CBBA3 + 7) = 0x90;
|
||||
VirtualProtect((BYTE*)0x00000001405CBBA3, 8, oldProtect, &bck);
|
||||
}
|
||||
|
||||
if (((*modState == 0) && (*pvId != lastPvId)) || ((lastModState == 1) && (*modState == 0)))
|
||||
{
|
||||
if ((lastModState == 1) && (*modState == 0))
|
||||
{
|
||||
*(int*)0x00000001411A8A28 = *(int*)0x00000001411A8A10;
|
||||
*(int*)(0x00000001411A8A28 + 4) = *(int*)(0x00000001411A8A10 + 4);
|
||||
*(int*)(0x00000001411A8A28 + 8) = *(int*)(0x00000001411A8A10 + 8);
|
||||
*(int*)(0x00000001411A8A28 + 12) = *(int*)(0x00000001411A8A10 + 12);
|
||||
*(int*)(0x00000001411A8A28 + 16) = *(int*)(0x00000001411A8A10 + 16);
|
||||
*(int*)(0x00000001411A8A28 + 18) = *(int*)(0x00000001411A8A10 + 18);
|
||||
}
|
||||
|
||||
initPvId = false;
|
||||
lastPvId = *pvId;
|
||||
lastModState = *modState;
|
||||
DWORD oldProtect, bck;
|
||||
VirtualProtect((BYTE*)0x00000001405CBBA3, 8, PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
*((BYTE*)0x00000001405CBBA3 + 0) = 0x42;
|
||||
*((BYTE*)0x00000001405CBBA3 + 1) = 0x89;
|
||||
*((BYTE*)0x00000001405CBBA3 + 2) = 0x84;
|
||||
*((BYTE*)0x00000001405CBBA3 + 3) = 0xb6;
|
||||
*((BYTE*)0x00000001405CBBA3 + 4) = 0xc0;
|
||||
*((BYTE*)0x00000001405CBBA3 + 5) = 0x01;
|
||||
*((BYTE*)0x00000001405CBBA3 + 6) = 0x00;
|
||||
*((BYTE*)0x00000001405CBBA3 + 7) = 0x00;
|
||||
VirtualProtect((BYTE*)0x00000001405CBBA3, 8, oldProtect, &bck);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (*(char*)0x000000014CC5E270 == 32)
|
||||
{
|
||||
DWORD oldProtect, bck;
|
||||
VirtualProtect((BYTE*)0x00000001405BC8E6, 3, PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
*((BYTE*)0x00000001405BC8E6 + 0) = 0x01;
|
||||
VirtualProtect((BYTE*)0x00000001405BC8E6, 3, oldProtect, &bck);
|
||||
|
||||
VirtualProtect((BYTE*)0x00000001405CBBA3, 8, PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
*((BYTE*)0x00000001405CBBA3 + 0) = 0x42;
|
||||
*((BYTE*)0x00000001405CBBA3 + 1) = 0x89;
|
||||
*((BYTE*)0x00000001405CBBA3 + 2) = 0x84;
|
||||
*((BYTE*)0x00000001405CBBA3 + 3) = 0xb6;
|
||||
*((BYTE*)0x00000001405CBBA3 + 4) = 0xc0;
|
||||
*((BYTE*)0x00000001405CBBA3 + 5) = 0x01;
|
||||
*((BYTE*)0x00000001405CBBA3 + 6) = 0x00;
|
||||
*((BYTE*)0x00000001405CBBA3 + 7) = 0x00;
|
||||
VirtualProtect((BYTE*)0x00000001405CBBA3, 8, oldProtect, &bck);
|
||||
|
||||
VirtualProtect((BYTE*)0x00000001405BCBE3, 2, PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
*((BYTE*)0x00000001405BCBE3 + 0) = 0x00;
|
||||
VirtualProtect((BYTE*)0x00000001405BCBE3, 2, oldProtect, &bck);
|
||||
|
||||
pvModuleLoaded = false;
|
||||
}
|
||||
else {
|
||||
if (!pvModuleLoaded)
|
||||
{
|
||||
pvModuleLoaded = true;
|
||||
DWORD oldProtect, bck;
|
||||
VirtualProtect((BYTE*)0x00000001405BC8E6, 3, PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
*((BYTE*)0x00000001405BC8E6 + 0) = 0x00;
|
||||
VirtualProtect((BYTE*)0x00000001405BC8E6, 3, oldProtect, &bck);
|
||||
|
||||
VirtualProtect((BYTE*)0x00000001405CBBA3, 8, PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
*((BYTE*)0x00000001405CBBA3 + 0) = 0x90;
|
||||
*((BYTE*)0x00000001405CBBA3 + 1) = 0x90;
|
||||
*((BYTE*)0x00000001405CBBA3 + 2) = 0x90;
|
||||
*((BYTE*)0x00000001405CBBA3 + 3) = 0x90;
|
||||
*((BYTE*)0x00000001405CBBA3 + 4) = 0x90;
|
||||
*((BYTE*)0x00000001405CBBA3 + 5) = 0x90;
|
||||
*((BYTE*)0x00000001405CBBA3 + 6) = 0x90;
|
||||
*((BYTE*)0x00000001405CBBA3 + 7) = 0x90;
|
||||
VirtualProtect((BYTE*)0x00000001405CBBA3, 8, oldProtect, &bck);
|
||||
|
||||
VirtualProtect((BYTE*)0x00000001405BCBE3, 2, PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
*((BYTE*)0x00000001405BCBE3 + 0) = 0x01;
|
||||
VirtualProtect((BYTE*)0x00000001405BCBE3, 2, oldProtect, &bck);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerDataManager::ApplyPatch()
|
||||
{
|
||||
DWORD oldProtect;
|
||||
VirtualProtect((void*)SET_DEFAULT_PLAYER_DATA_ADDRESS, sizeof(uint8_t), PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
{
|
||||
// prevent the PlayerData from being reset
|
||||
*(uint8_t*)(SET_DEFAULT_PLAYER_DATA_ADDRESS) = RET_OPCODE;
|
||||
}
|
||||
VirtualProtect((void*)SET_DEFAULT_PLAYER_DATA_ADDRESS, sizeof(uint8_t), oldProtect, &oldProtect);
|
||||
|
||||
// allow player to select the module and extra item
|
||||
VirtualProtect((void*)MODSELECTOR_CHECK_FUNCTION_ERRRET_ADDRESS, sizeof(byte) * 2, PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
{
|
||||
*(byte*)(MODSELECTOR_CHECK_FUNCTION_ERRRET_ADDRESS) = 0xB0; // xor al,al -> ld al,1
|
||||
*(byte*)(MODSELECTOR_CHECK_FUNCTION_ERRRET_ADDRESS + 0x1) = 0x01;
|
||||
}
|
||||
VirtualProtect((void*)MODSELECTOR_CHECK_FUNCTION_ERRRET_ADDRESS, sizeof(byte) * 2, oldProtect, &oldProtect);
|
||||
|
||||
// fix annoying behavior of closing after changing module or item (don't yet know the reason, maybe NW/Card checks)
|
||||
{
|
||||
VirtualProtect((void*)MODSELECTOR_CLOSE_AFTER_MODULE, sizeof(uint8_t), PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
{
|
||||
*(uint8_t*)(MODSELECTOR_CLOSE_AFTER_MODULE) = JNE_OPCODE;
|
||||
}
|
||||
VirtualProtect((void*)MODSELECTOR_CLOSE_AFTER_MODULE, sizeof(uint8_t), oldProtect, &oldProtect);
|
||||
VirtualProtect((void*)MODSELECTOR_CLOSE_AFTER_CUSTOMIZE, sizeof(uint8_t), PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
{
|
||||
*(uint8_t*)(MODSELECTOR_CLOSE_AFTER_CUSTOMIZE) = JNE_OPCODE;
|
||||
}
|
||||
VirtualProtect((void*)MODSELECTOR_CLOSE_AFTER_CUSTOMIZE, sizeof(uint8_t), oldProtect, &oldProtect);
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerDataManager::LoadConfig()
|
||||
{
|
||||
if (playerData == nullptr)
|
||||
return;
|
||||
|
||||
FileSystem::ConfigFile config(framework::GetModuleDirectory(), PLAYER_DATA_FILE_NAME);
|
||||
|
||||
if (!config.OpenRead())
|
||||
return;
|
||||
|
||||
if (customPlayerData != nullptr)
|
||||
delete customPlayerData;
|
||||
|
||||
customPlayerData = new CustomPlayerData();
|
||||
config.TryGetValue("player_name", &customPlayerData->PlayerName);
|
||||
config.TryGetValue("level_name", &customPlayerData->LevelName);
|
||||
|
||||
customPlayerData->LevelPlateId = config.GetIntegerValue("level_plate_id");
|
||||
customPlayerData->SkinEquip = config.GetIntegerValue("skin_equip");
|
||||
customPlayerData->BtnSeEquip = config.GetIntegerValue("btn_se_equip");
|
||||
customPlayerData->SlideSeEquip = config.GetIntegerValue("slide_se_equip");
|
||||
customPlayerData->ChainslideSeEquip = config.GetIntegerValue("chainslide_se_equip");
|
||||
customPlayerData->ShowExcellentClearBorder = config.GetBooleanValue("border_excellent");
|
||||
customPlayerData->ShowGreatClearBorder = config.GetBooleanValue("border_great");
|
||||
customPlayerData->UseCard = config.GetBooleanValue("use_card");
|
||||
customPlayerData->GameModifierOptions = config.GetBooleanValue("gamemode_options");
|
||||
moduleCardWorkaround = config.GetBooleanValue("module_card_workaround");
|
||||
|
||||
if (moduleCardWorkaround) {
|
||||
if (!customPlayerData->UseCard)
|
||||
{
|
||||
DWORD oldProtect, bck;
|
||||
VirtualProtect((BYTE*)0x000000014010523F, 3, PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
*((BYTE*)0x0000000140105239 + 0) = 0x30;
|
||||
*((BYTE*)0x0000000140105239 + 1) = 0xC0;
|
||||
*((BYTE*)0x0000000140105239 + 2) = 0x90;
|
||||
VirtualProtect((BYTE*)0x0000000140105239, 3, oldProtect, &bck);
|
||||
|
||||
VirtualProtect((BYTE*)0x00000001405BCC48, 6, PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
*((BYTE*)0x00000001405BCC48 + 0) = 0x90;
|
||||
*((BYTE*)0x00000001405BCC48 + 1) = 0x90;
|
||||
*((BYTE*)0x00000001405BCC48 + 2) = 0x90;
|
||||
*((BYTE*)0x00000001405BCC48 + 3) = 0x90;
|
||||
*((BYTE*)0x00000001405BCC48 + 4) = 0x90;
|
||||
*((BYTE*)0x00000001405BCC48 + 5) = 0x90;
|
||||
VirtualProtect((BYTE*)0x00000001405BCC48, 6, oldProtect, &bck);
|
||||
|
||||
VirtualProtect((BYTE*)0x00000001405BC8E6, 3, PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
*((BYTE*)0x00000001405BC8E6 + 0) = 0x01;
|
||||
VirtualProtect((BYTE*)0x00000001405BC8E6, 3, oldProtect, &bck);
|
||||
|
||||
}
|
||||
else {
|
||||
DWORD oldProtect, bck;
|
||||
VirtualProtect((BYTE*)0x00000001405BC8E6, 3, PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
*((BYTE*)0x00000001405BC8E6 + 0) = 0x00;
|
||||
VirtualProtect((BYTE*)0x00000001405BC8E6, 3, oldProtect, &bck);
|
||||
|
||||
VirtualProtect((BYTE*)0x00000001405BCC48, 6, PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
*((BYTE*)0x00000001405BCC48 + 0) = 0xC7;
|
||||
*((BYTE*)0x00000001405BCC48 + 1) = 0x03;
|
||||
*((BYTE*)0x00000001405BCC48 + 2) = 0x00;
|
||||
*((BYTE*)0x00000001405BCC48 + 3) = 0x00;
|
||||
*((BYTE*)0x00000001405BCC48 + 4) = 0x00;
|
||||
*((BYTE*)0x00000001405BCC48 + 5) = 0x00;
|
||||
VirtualProtect((BYTE*)0x00000001405BCC48, 6, oldProtect, &bck);
|
||||
|
||||
VirtualProtect((BYTE*)0x000000014010523F, 3, PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
*((BYTE*)0x0000000140105239 + 0) = 0x0F;
|
||||
*((BYTE*)0x0000000140105239 + 1) = 0x94;
|
||||
*((BYTE*)0x0000000140105239 + 2) = 0xC1;
|
||||
VirtualProtect((BYTE*)0x0000000140105239, 3, oldProtect, &bck);
|
||||
|
||||
//just incase the player is reloading
|
||||
VirtualProtect((BYTE*)0x00000001405CBBA3, 8, PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
*((BYTE*)0x00000001405CBBA3 + 0) = 0x42;
|
||||
*((BYTE*)0x00000001405CBBA3 + 1) = 0x89;
|
||||
*((BYTE*)0x00000001405CBBA3 + 2) = 0x84;
|
||||
*((BYTE*)0x00000001405CBBA3 + 3) = 0xb6;
|
||||
*((BYTE*)0x00000001405CBBA3 + 4) = 0xc0;
|
||||
*((BYTE*)0x00000001405CBBA3 + 5) = 0x01;
|
||||
*((BYTE*)0x00000001405CBBA3 + 6) = 0x00;
|
||||
*((BYTE*)0x00000001405CBBA3 + 7) = 0x00;
|
||||
VirtualProtect((BYTE*)0x00000001405CBBA3, 8, oldProtect, &bck);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerDataManager::ApplyCustomData()
|
||||
{
|
||||
// don't want to overwrite the default values
|
||||
auto setIfNotEqual = [](int *target, int value, int comparison)
|
||||
{
|
||||
if (value != comparison)
|
||||
*target = value;
|
||||
};
|
||||
|
||||
setIfNotEqual(&playerData->level_plate_id, customPlayerData->LevelPlateId, 0);
|
||||
setIfNotEqual(&playerData->skin_equip, customPlayerData->SkinEquip, 0);
|
||||
setIfNotEqual(&playerData->btn_se_equip, customPlayerData->BtnSeEquip, -1);
|
||||
setIfNotEqual(&playerData->slide_se_equip, customPlayerData->SlideSeEquip, -1);
|
||||
setIfNotEqual(&playerData->chainslide_se_equip, customPlayerData->ChainslideSeEquip, -1);
|
||||
|
||||
// Display clear borders on the progress bar
|
||||
*(byte*)(PLAYER_DATA_ADDRESS + 0xD94) = (customPlayerData->ShowExcellentClearBorder << 1) | (customPlayerData->ShowGreatClearBorder);
|
||||
|
||||
if (customPlayerData->UseCard)
|
||||
playerData->use_card = 1; // required to allow for module selection
|
||||
|
||||
if (customPlayerData->GameModifierOptions)
|
||||
playerData->game_opts = 1; // hi-speed, etc..
|
||||
|
||||
memset((void*)MODULE_TABLE_START, 0xFF, 128);
|
||||
memset((void*)ITEM_TABLE_START, 0xFF, 128);
|
||||
|
||||
if (customPlayerData->PlayerName != nullptr)
|
||||
{
|
||||
playerData->field_DC = 0x10;
|
||||
playerData->player_name = (char*)customPlayerData->PlayerName->c_str();
|
||||
}
|
||||
|
||||
|
||||
if (customPlayerData->LevelName != nullptr)
|
||||
{
|
||||
playerData->level_name = (char*)customPlayerData->LevelName->c_str();
|
||||
playerData->field_110 = 0xFF;
|
||||
playerData->field_118 = 0x1F;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
#include "EmulatorComponent.h"
|
||||
#include "PlayerData.h"
|
||||
#include "CustomPlayerData.h"
|
||||
#include <string>
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
class PlayerDataManager : public EmulatorComponent
|
||||
{
|
||||
public:
|
||||
PlayerDataManager();
|
||||
~PlayerDataManager();
|
||||
|
||||
virtual const char* GetDisplayName() override;
|
||||
|
||||
virtual void Initialize(ComponentsManager*) override;
|
||||
virtual void Update() override;
|
||||
|
||||
private:
|
||||
PlayerData* playerData;
|
||||
CustomPlayerData* customPlayerData;
|
||||
int lastPvId = -1;
|
||||
bool initPvId = true;
|
||||
bool pvModuleLoaded = true;
|
||||
bool moduleCardWorkaround = true;
|
||||
int lastModState = 0;
|
||||
void ApplyPatch();
|
||||
void LoadConfig();
|
||||
void ApplyCustomData();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
#include "ScaleComponent.h"
|
||||
#include <iostream>
|
||||
#include <Windows.h>
|
||||
#include "../Constants.h"
|
||||
#include <stdio.h>
|
||||
#include "../framework.h"
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <tchar.h>
|
||||
#include <GL/freeglut.h>
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
|
||||
ScaleComponent::ScaleComponent()
|
||||
{
|
||||
}
|
||||
|
||||
ScaleComponent::~ScaleComponent()
|
||||
{
|
||||
}
|
||||
|
||||
const char* ScaleComponent::GetDisplayName()
|
||||
{
|
||||
return "scale_component";
|
||||
}
|
||||
|
||||
void ScaleComponent::Initialize(ComponentsManager*)
|
||||
{
|
||||
{
|
||||
DWORD oldProtect, bck;
|
||||
VirtualProtect((BYTE*)0x00000001404ACD24, 7, PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
*((byte*)0x00000001404ACD24 + 0) = 0x44;
|
||||
*((byte*)0x00000001404ACD24 + 1) = 0x8B;
|
||||
*((byte*)0x00000001404ACD24 + 2) = 0x0D;
|
||||
*((byte*)0x00000001404ACD24 + 3) = 0xD1;
|
||||
*((byte*)0x00000001404ACD24 + 4) = 0x08;
|
||||
*((byte*)0x00000001404ACD24 + 5) = 0xD0;
|
||||
*((byte*)0x00000001404ACD24 + 6) = 0x00;
|
||||
VirtualProtect((BYTE*)0x00000001404ACD24, 7, oldProtect, &bck);
|
||||
}
|
||||
{
|
||||
DWORD oldProtect, bck;
|
||||
VirtualProtect((BYTE*)0x00000001404ACD2B, 7, PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
*((byte*)0x00000001404ACD2B + 0) = 0x44;
|
||||
*((byte*)0x00000001404ACD2B + 1) = 0x8B;
|
||||
*((byte*)0x00000001404ACD2B + 2) = 0x05;
|
||||
*((byte*)0x00000001404ACD2B + 3) = 0xC6;
|
||||
*((byte*)0x00000001404ACD2B + 4) = 0x08;
|
||||
*((byte*)0x00000001404ACD2B + 5) = 0xD0;
|
||||
*((byte*)0x00000001404ACD2B + 6) = 0x00;
|
||||
VirtualProtect((BYTE*)0x00000001404ACD2B, 7, oldProtect, &bck);
|
||||
}
|
||||
{
|
||||
DWORD oldProtect, bck;
|
||||
VirtualProtect((BYTE*)0x00000001405030A0, 6, PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
*((byte*)0x00000001405030A0 + 0) = 0x90;
|
||||
*((byte*)0x00000001405030A0 + 1) = 0x90;
|
||||
*((byte*)0x00000001405030A0 + 2) = 0x90;
|
||||
*((byte*)0x00000001405030A0 + 3) = 0x90;
|
||||
*((byte*)0x00000001405030A0 + 4) = 0x90;
|
||||
*((byte*)0x00000001405030A0 + 5) = 0x90;
|
||||
VirtualProtect((BYTE*)0x00000001404ACD2B, 6, oldProtect, &bck);
|
||||
}
|
||||
}
|
||||
|
||||
void ScaleComponent::Update()
|
||||
{
|
||||
uiAspectRatio = (float*)UI_ASPECT_RATIO;
|
||||
uiWidth = (float*)UI_WIDTH_ADDRESS;
|
||||
uiHeight = (float*)UI_HEIGHT_ADDRESS;
|
||||
fb1Height = (int*)FB1_HEIGHT_ADDRESS;
|
||||
fb1Width = (int*)FB1_WIDTH_ADDRESS;
|
||||
//fb2Height = (int*)FB2_HEIGHT_ADDRESS;
|
||||
//fb2Width = (int*)FB2_WIDTH_ADDRESS;
|
||||
fbAspectRatio = (double*)FB_ASPECT_RATIO;
|
||||
RECT hWindow;
|
||||
GetClientRect(TLAC::framework::DivaWindowHandle, &hWindow);
|
||||
*uiAspectRatio = (float)(hWindow.right - hWindow.left) / (float)(hWindow.bottom - hWindow.top);
|
||||
*fbAspectRatio = (double)(hWindow.right - hWindow.left) / (double)(hWindow.bottom - hWindow.top);
|
||||
*uiWidth = hWindow.right - hWindow.left;
|
||||
*uiHeight = hWindow.bottom - hWindow.top;
|
||||
*fb1Width = hWindow.right - hWindow.left;
|
||||
*fb1Height = hWindow.bottom - hWindow.top;
|
||||
//*fb2Width = hWindow.right - hWindow.left;
|
||||
//*fb2Height = hWindow.bottom - hWindow.top;
|
||||
|
||||
*((int*)0x00000001411AD608) = 0;
|
||||
|
||||
*((int*)0x0000000140EDA8E4) = *(int*)0x0000000140EDA8BC;
|
||||
*((int*)0x0000000140EDA8E8) = *(int*)0x0000000140EDA8C0;
|
||||
|
||||
*(float*)0x00000001411A1900 = 0;
|
||||
*(float*)0x00000001411A1904 = (float)*(int*)0x0000000140EDA8BC;
|
||||
*(float*)0x00000001411A1908 = (float)*(int*)0x0000000140EDA8C0;
|
||||
//*((int*)0x00000001411AD5F8) = hWindow.right - hWindow.left;
|
||||
//*((int*)0x00000001411AD5FC) = hWindow.bottom - hWindow.top;
|
||||
|
||||
//*((int*)0x00000001411ABB48) = hWindow.right - hWindow.left;
|
||||
//*((int*)0x00000001411ABB4C) = hWindow.bottom - hWindow.top;
|
||||
|
||||
//*((int*)0x00000001411ABB5C) = (int)(*((int*)0x00000001411ABB54) * ((float)8 / (float)9)); //wtf??
|
||||
}
|
||||
|
||||
void ScaleComponent::UpdateInput()
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
#include "EmulatorComponent.h"
|
||||
#include "GameState.h"
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
class ScaleComponent : public EmulatorComponent
|
||||
{
|
||||
public:
|
||||
ScaleComponent();
|
||||
~ScaleComponent();
|
||||
|
||||
virtual const char* GetDisplayName() override;
|
||||
|
||||
virtual void Initialize(ComponentsManager*) override;
|
||||
virtual void Update() override;
|
||||
virtual void UpdateInput() override;
|
||||
|
||||
const int updatesPerFrame = 39;
|
||||
|
||||
float* uiAspectRatio;
|
||||
float* uiWidth;
|
||||
float* uiHeight;
|
||||
|
||||
int* fb1Width;
|
||||
int* fb1Height;
|
||||
int* fb2Width;
|
||||
int* fb2Height;
|
||||
|
||||
double* fbAspectRatio;
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#include "StageManager.h"
|
||||
#include "../Constants.h"
|
||||
#include <windows.h>
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
StageManager::StageManager()
|
||||
{
|
||||
}
|
||||
|
||||
StageManager::~StageManager()
|
||||
{
|
||||
}
|
||||
|
||||
const char* StageManager::GetDisplayName()
|
||||
{
|
||||
return "stage_manager";
|
||||
}
|
||||
|
||||
void StageManager::Initialize(ComponentsManager*)
|
||||
{
|
||||
// add the offset between moving 2 into ebx and the start of the function
|
||||
int32_t* playCount = (int32_t*)(((uint8_t*)PLAYS_PER_SESSION_GETTER_ADDRESS) + 0x7);
|
||||
|
||||
DWORD oldProtect;
|
||||
VirtualProtect(playCount, sizeof(int32_t), PAGE_EXECUTE_READWRITE, &oldProtect);
|
||||
|
||||
// set ’Ê�탂�[ƒh per session play count
|
||||
*playCount = GetPlayCount();
|
||||
}
|
||||
|
||||
void StageManager::Update()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t StageManager::GetPlayCount()
|
||||
{
|
||||
return INT32_MAX;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include "EmulatorComponent.h"
|
||||
#include <stdint.h>
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
class StageManager : public EmulatorComponent
|
||||
{
|
||||
public:
|
||||
StageManager();
|
||||
~StageManager();
|
||||
|
||||
virtual const char* GetDisplayName() override;
|
||||
|
||||
virtual void Initialize(ComponentsManager*) override;
|
||||
virtual void Update() override;
|
||||
|
||||
private:
|
||||
int32_t GetPlayCount();
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#include "SysTimer.h"
|
||||
#include "../Constants.h"
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
SysTimer::SysTimer()
|
||||
{
|
||||
}
|
||||
|
||||
SysTimer::~SysTimer()
|
||||
{
|
||||
}
|
||||
|
||||
const char* SysTimer::GetDisplayName()
|
||||
{
|
||||
return "sys_timer";
|
||||
}
|
||||
|
||||
void SysTimer::Initialize(ComponentsManager*)
|
||||
{
|
||||
selPvTime = GetSysTimePtr((void*)SEL_PV_TIME_ADDRESS);
|
||||
}
|
||||
|
||||
void SysTimer::Update()
|
||||
{
|
||||
// account for the decrement that occures during this frame
|
||||
*selPvTime = SEL_PV_FREEZE_TIME * SYS_TIME_FACTOR + 1;
|
||||
}
|
||||
|
||||
int* SysTimer::GetSysTimePtr(void *address)
|
||||
{
|
||||
return (int*)address;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
#include "EmulatorComponent.h"
|
||||
|
||||
namespace TLAC::Components
|
||||
{
|
||||
class SysTimer : public EmulatorComponent
|
||||
{
|
||||
const int SYS_TIME_FACTOR = 60;
|
||||
const int SEL_PV_FREEZE_TIME = 39;
|
||||
|
||||
public:
|
||||
SysTimer();
|
||||
~SysTimer();
|
||||
|
||||
virtual const char* GetDisplayName() override;
|
||||
|
||||
virtual void Initialize(ComponentsManager*) override;
|
||||
virtual void Update() override;
|
||||
|
||||
private:
|
||||
int* selPvTime;
|
||||
int* GetSysTimePtr(void *address);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
constexpr uint8_t NOP_OPCODE = 0x90;
|
||||
constexpr uint8_t RET_OPCODE = 0xC3;
|
||||
constexpr uint8_t JMP_OPCODE = 0xE9;
|
||||
constexpr uint8_t JNE_OPCODE = 0x85;
|
||||
|
||||
//constexpr uint64_t ENGINE_UPDATE_HOOK_TARGET_ADDRESS = 0x000000014018CC40;
|
||||
constexpr uint64_t ENGINE_UPDATE_INPUT_ADDRESS = 0x000000014018CBB0;
|
||||
|
||||
constexpr uint64_t CURRENT_GAME_STATE_ADDRESS = 0x0000000140EDA810;
|
||||
constexpr uint64_t RESOLUTION_WIDTH_ADDRESS = 0x0000000140EDA8BC;
|
||||
constexpr uint64_t RESOLUTION_HEIGHT_ADDRESS = 0x0000000140EDA8C0;
|
||||
|
||||
constexpr uint64_t SYSTEM_WARNING_ELAPSED_ADDRESS = (0x00000001411A1430 + 0x68);
|
||||
constexpr uint64_t DATA_INIT_STATE_ADDRESS = 0x0000000140EDA7A8;
|
||||
|
||||
constexpr uint64_t AET_FRAME_DURATION_ADDRESS = 0x00000001409A0A58;
|
||||
constexpr uint64_t PV_FRAME_RATE_ADDRESS = 0x0000000140EDA7CC;
|
||||
constexpr uint64_t FRAME_SPEED_ADDRESS = 0x0000000140EDA798;
|
||||
constexpr uint64_t FRAME_RATE_ADDRESS = 0x0000000140EDA6D0;
|
||||
|
||||
constexpr uint64_t DW_GUI_DISPLAY_INSTANCE_PTR_ADDRESS = 0x0000000141190108;
|
||||
constexpr uint64_t INPUT_STATE_PTR_ADDRESS = 0x0000000140EDA330;
|
||||
constexpr uint64_t SLIDER_CTRL_TASK_ADDRESS = 0x000000014CC5DE40;
|
||||
constexpr uint64_t TASK_TOUCH_ADDRESS = 0x000000014CC9EC30;
|
||||
constexpr uint64_t SEL_PV_TIME_ADDRESS = 0x000000014CC12498;
|
||||
constexpr uint64_t PLAYER_DATA_ADDRESS = 0x00000001411A8850;
|
||||
constexpr uint64_t SET_DEFAULT_PLAYER_DATA_ADDRESS = 0x00000001404A7370;
|
||||
constexpr uint64_t PLAYS_PER_SESSION_GETTER_ADDRESS = 0x000000014038AEE0;
|
||||
constexpr uint64_t PV_SEL_SLOTS_TO_SCROLL = 0x000000014CC12470;
|
||||
constexpr uint64_t PV_SEL_SLOTS_CONST = 0x000000014CC119C8;
|
||||
constexpr uint64_t MODULE_SEL_SLOTS_TO_SCROLL = 0x00000001418047EC;
|
||||
constexpr uint64_t MODULE_IS_RECOMMENDED = 0x00000001418047E0;
|
||||
|
||||
constexpr uint64_t CAMERA_ADDRESS = 0x0000000140FBC2C0;
|
||||
constexpr uint64_t CAMERA_POS_SETTER_ADDRESS = 0x00000001401F9460;
|
||||
constexpr uint64_t CAMERA_INTR_SETTER_ADDRESS = 0x00000001401F93F0;
|
||||
constexpr uint64_t CAMERA_ROT_SETTER_ADDRESS = 0x00000001401F9480;
|
||||
constexpr uint64_t CAMERA_PERS_SETTER_ADDRESS = 0x00000001401F9430;
|
||||
|
||||
constexpr uint64_t UPDATE_TASKS_ADDRESS = 0x000000014019B980;
|
||||
constexpr uint64_t GLUT_SET_CURSOR_ADDRESS = 0x00000001408B68E6;
|
||||
constexpr uint64_t CHANGE_MODE_ADDRESS = 0x00000001401953D0;
|
||||
constexpr uint64_t CHANGE_SUB_MODE_ADDRESS = 0x0000000140195260;
|
||||
|
||||
constexpr uint64_t TGT_TYPE_BASE_ADDRESS = 0x0000000140D0B69C;
|
||||
constexpr uint64_t TGT_REMAINING_DURATION_BASE_ADDRESS = 0x0000000140D0B6A0;
|
||||
constexpr uint64_t TGT_HIT_STATE_BASE_ADDRESS = 0x0000000140D0BAE4;
|
||||
constexpr uint64_t TGT_ON_SCREEN_ADDRESS = 0x0000000140D0B678;
|
||||
|
||||
constexpr uint64_t HOLD_STATE_ADDRESS = 0x0000000140D1E20C;
|
||||
constexpr uint64_t MAX_HOLD_STATE_ADDRESS = 0x0000000140D1E234;
|
||||
|
||||
constexpr uint64_t CHECK_SOMETHING_SET_MODULE_ADDRESS = 0x0000000140581C78;
|
||||
constexpr uint64_t MODSELECTOR_CHECK_FUNCTION_ERRRET_ADDRESS = 0x00000001405869AD;
|
||||
constexpr uint64_t MODSELECTOR_CLOSE_AFTER_MODULE = 0x0000000140583B45;
|
||||
constexpr uint64_t MODSELECTOR_CLOSE_AFTER_CUSTOMIZE = 0x0000000140583C8C;
|
||||
constexpr uint64_t MODULE_TABLE_START = PLAYER_DATA_ADDRESS + 0x140;
|
||||
constexpr uint64_t MODULE_TABLE_END = MODULE_TABLE_START + 128;
|
||||
constexpr uint64_t ITEM_TABLE_START = PLAYER_DATA_ADDRESS + 0x2B8;
|
||||
constexpr uint64_t ITEM_TABLE_END = ITEM_TABLE_START + 128;
|
||||
|
||||
constexpr uint64_t FB_WIDTH_ADDRESS = 0x00000001411ABCA8;
|
||||
constexpr uint64_t FB_HEIGHT_ADDRESS = 0x00000001411ABCAC;
|
||||
constexpr uint64_t FB1_WIDTH_ADDRESS = 0x00000001411AD5F8;
|
||||
constexpr uint64_t FB1_HEIGHT_ADDRESS = 0x00000001411AD5FC;
|
||||
constexpr uint64_t FB2_WIDTH_ADDRESS = 0x0000000140EDA8E4;
|
||||
constexpr uint64_t FB2_HEIGHT_ADDRESS = 0x0000000140EDA8E8;
|
||||
|
||||
constexpr uint64_t FB_RESOLUTION_WIDTH_ADDRESS = 0x00000001411ABB50;
|
||||
constexpr uint64_t FB_RESOLUTION_HEIGHT_ADDRESS = 0x00000001411ABB54;
|
||||
|
||||
constexpr uint64_t UI_WIDTH_ADDRESS = 0x000000014CC621E4;
|
||||
constexpr uint64_t UI_HEIGHT_ADDRESS = 0x000000014CC621E8;
|
||||
|
||||
constexpr uint64_t FB_ASPECT_RATIO = 0x0000000140FBC2E8;
|
||||
constexpr uint64_t UI_ASPECT_RATIO = 0x000000014CC621D0;
|
||||
|
||||
#define XINPUT_A 0x00
|
||||
#define XINPUT_B 0x01
|
||||
#define XINPUT_X 0x02
|
||||
#define XINPUT_Y 0x03
|
||||
#define XINPUT_UP 0x10
|
||||
#define XINPUT_DOWN 0x11
|
||||
#define XINPUT_LEFT 0x12
|
||||
#define XINPUT_RIGHT 0x13
|
||||
#define XINPUT_LS 0x20
|
||||
#define XINPUT_RS 0x21
|
||||
#define XINPUT_LT 0x22
|
||||
#define XINPUT_RT 0x23
|
||||
#define XINPUT_LSB 0x24
|
||||
#define XINPUT_RSB 0x25
|
||||
#define XINPUT_START 0x30
|
||||
#define XINPUT_BACK 0x31
|
||||
#define XINPUT_LUP 0x40
|
||||
#define XINPUT_LDOWN 0x41
|
||||
#define XINPUT_LLEFT 0x42
|
||||
#define XINPUT_LRIGHT 0x43
|
||||
#define XINPUT_RUP 0x50
|
||||
#define XINPUT_RDOWN 0x51
|
||||
#define XINPUT_RLEFT 0x52
|
||||
#define XINPUT_RRIGHT 0x53
|
||||
@@ -0,0 +1,72 @@
|
||||
#include <stdio.h>
|
||||
#include "ConfigFile.h"
|
||||
#include "../Utilities/Operations.h"
|
||||
|
||||
namespace TLAC::FileSystem
|
||||
{
|
||||
ConfigFile::ConfigFile(const std::string &path) : TextFile(path)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ConfigFile::ConfigFile(const std::string &directory, const std::string &file) : TextFile(directory, file)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool ConfigFile::TryGetValue(const std::string &key, std::string **value)
|
||||
{
|
||||
auto pair = ConfigMap.find(key);
|
||||
bool found = pair != ConfigMap.end();
|
||||
|
||||
*value = found ? new std::string(pair->second) : nullptr;
|
||||
return found;
|
||||
}
|
||||
|
||||
int ConfigFile::GetIntegerValue(const std::string& key)
|
||||
{
|
||||
auto pair = ConfigMap.find(key);
|
||||
bool found = pair != ConfigMap.end();
|
||||
|
||||
return found ? atoi(pair->second.c_str()) : 0;
|
||||
}
|
||||
|
||||
bool ConfigFile::GetBooleanValue(const std::string& key)
|
||||
{
|
||||
auto pair = ConfigMap.find(key);
|
||||
bool found = pair != ConfigMap.end();
|
||||
|
||||
return found ? pair->second == "true" : false;
|
||||
}
|
||||
|
||||
float ConfigFile::GetFloatValue(const std::string & key)
|
||||
{
|
||||
auto pair = ConfigMap.find(key);
|
||||
bool found = pair != ConfigMap.end();
|
||||
|
||||
return found ? (float)atof(pair->second.c_str()) : 0.0f;
|
||||
}
|
||||
|
||||
void ConfigFile::Parse(std::ifstream &fileStream)
|
||||
{
|
||||
std::string line;
|
||||
|
||||
while (std::getline(fileStream, line))
|
||||
{
|
||||
if (IsComment(line))
|
||||
continue;
|
||||
|
||||
auto splitline = Utilities::Split(line, "=");
|
||||
|
||||
for (auto &line : splitline)
|
||||
Utilities::Trim(line);
|
||||
|
||||
ConfigMap.insert(std::make_pair(splitline[0], splitline[1]));
|
||||
}
|
||||
}
|
||||
|
||||
bool ConfigFile::IsComment(const std::string &line)
|
||||
{
|
||||
return line.size() <= 0 || line[0] == '#' || line[0] == '[' || line._Starts_with("//");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "TextFile.h"
|
||||
#include <unordered_map>
|
||||
|
||||
namespace TLAC::FileSystem
|
||||
{
|
||||
class ConfigFile : public TextFile
|
||||
{
|
||||
public:
|
||||
ConfigFile(const std::string &path);
|
||||
ConfigFile(const std::string &directory, const std::string &file);
|
||||
|
||||
std::unordered_map<std::string, std::string> ConfigMap;
|
||||
|
||||
bool TryGetValue(const std::string &key, std::string **value);
|
||||
int GetIntegerValue(const std::string& key);
|
||||
bool GetBooleanValue(const std::string& key);
|
||||
float GetFloatValue(const std::string& key);
|
||||
|
||||
protected:
|
||||
virtual void Parse(std::ifstream &fileStream) override;
|
||||
|
||||
private:
|
||||
bool IsComment(const std::string &line);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
#include "TextFile.h"
|
||||
#include <filesystem>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace TLAC::FileSystem
|
||||
{
|
||||
TextFile::TextFile(const std::string &path)
|
||||
{
|
||||
FileName = path;
|
||||
}
|
||||
|
||||
TextFile::TextFile(const std::string &directory, const std::string &file)
|
||||
{
|
||||
auto fullPath = directory + "/" + file;
|
||||
FileName = fullPath;
|
||||
}
|
||||
|
||||
TextFile::~TextFile()
|
||||
{
|
||||
}
|
||||
|
||||
bool TextFile::OpenRead()
|
||||
{
|
||||
fs::path configPath = fs::u8path(FileName);
|
||||
|
||||
if (!fs::exists(configPath))
|
||||
return false;
|
||||
|
||||
std::ifstream fileStream(configPath.wstring().c_str());
|
||||
|
||||
if (!fileStream.is_open())
|
||||
return false;
|
||||
|
||||
Parse(fileStream);
|
||||
|
||||
fileStream.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
|
||||
namespace TLAC::FileSystem
|
||||
{
|
||||
class TextFile
|
||||
{
|
||||
public:
|
||||
std::string FileName;
|
||||
|
||||
TextFile(const std::string &path);
|
||||
TextFile(const std::string &directory, const std::string &file);
|
||||
~TextFile();
|
||||
|
||||
bool OpenRead();
|
||||
|
||||
protected:
|
||||
virtual void Parse(std::ifstream &fileStream) = 0;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
#include "Binding.h"
|
||||
|
||||
namespace TLAC::Input
|
||||
{
|
||||
Binding::Binding()
|
||||
{
|
||||
}
|
||||
|
||||
Binding::~Binding()
|
||||
{
|
||||
for (auto& binding : InputBindings)
|
||||
delete binding;
|
||||
}
|
||||
|
||||
void Binding::AddBinding(IInputBinding* inputBinding)
|
||||
{
|
||||
InputBindings.push_back(inputBinding);
|
||||
}
|
||||
|
||||
bool Binding::AnyDown()
|
||||
{
|
||||
for (const auto& binding : InputBindings)
|
||||
{
|
||||
if (binding->IsDown())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Binding::AnyTapped()
|
||||
{
|
||||
for (const auto& binding : InputBindings)
|
||||
{
|
||||
if (binding->IsTapped())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Binding::AnyReleased()
|
||||
{
|
||||
for (const auto& binding : InputBindings)
|
||||
{
|
||||
if (binding->IsReleased())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int Binding::GetDownCount()
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for (const auto& binding : InputBindings)
|
||||
{
|
||||
if (binding->IsDown())
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int Binding::GetTappedCount()
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for (const auto& binding : InputBindings)
|
||||
{
|
||||
if (binding->IsTapped())
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int Binding::GetReleasedCount()
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for (const auto& binding : InputBindings)
|
||||
{
|
||||
if (binding->IsReleased())
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include "IInputBinding.h"
|
||||
|
||||
namespace TLAC::Input
|
||||
{
|
||||
class Binding
|
||||
{
|
||||
public:
|
||||
std::vector<IInputBinding*> InputBindings;
|
||||
|
||||
Binding();
|
||||
~Binding();
|
||||
|
||||
void AddBinding(IInputBinding* inputBinding);
|
||||
|
||||
bool AnyDown();
|
||||
bool AnyTapped();
|
||||
bool AnyReleased();
|
||||
|
||||
int GetDownCount();
|
||||
int GetTappedCount();
|
||||
int GetReleasedCount();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
#include "Ds4Binding.h"
|
||||
|
||||
namespace TLAC::Input
|
||||
{
|
||||
#define Ds4InstanceCheckDefault(checkFunc) (DualShock4::InstanceInitialized() ? DualShock4::GetInstance()->checkFunc : false)
|
||||
|
||||
Ds4Binding::Ds4Binding(Ds4Button button) : Button(button)
|
||||
{
|
||||
}
|
||||
|
||||
Ds4Binding::~Ds4Binding()
|
||||
{
|
||||
}
|
||||
|
||||
bool Ds4Binding::IsDown()
|
||||
{
|
||||
return Ds4InstanceCheckDefault(IsDown(Button));
|
||||
}
|
||||
|
||||
bool Ds4Binding::IsTapped()
|
||||
{
|
||||
return Ds4InstanceCheckDefault(IsTapped(Button));
|
||||
}
|
||||
|
||||
bool Ds4Binding::IsReleased()
|
||||
{
|
||||
return Ds4InstanceCheckDefault(IsReleased(Button));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include "IInputBinding.h"
|
||||
#include "../DirectInput/Ds4/DualShock4.h"
|
||||
|
||||
namespace TLAC::Input
|
||||
{
|
||||
class Ds4Binding : public IInputBinding
|
||||
{
|
||||
public:
|
||||
Ds4Button Button;
|
||||
|
||||
Ds4Binding(Ds4Button button);
|
||||
~Ds4Binding();
|
||||
|
||||
bool IsDown() override;
|
||||
bool IsTapped() override;
|
||||
bool IsReleased() override;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
namespace TLAC::Input
|
||||
{
|
||||
class IInputBinding
|
||||
{
|
||||
public:
|
||||
virtual bool IsDown() = 0;
|
||||
virtual bool IsTapped() = 0;
|
||||
virtual bool IsReleased() = 0;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#include "KeyboardBinding.h"
|
||||
|
||||
namespace TLAC::Input
|
||||
{
|
||||
KeyboardBinding::KeyboardBinding(BYTE keycode) : Keycode(keycode)
|
||||
{
|
||||
}
|
||||
|
||||
KeyboardBinding::~KeyboardBinding()
|
||||
{
|
||||
}
|
||||
|
||||
bool KeyboardBinding::IsDown()
|
||||
{
|
||||
return Keyboard::GetInstance()->IsDown(Keycode);
|
||||
}
|
||||
|
||||
bool KeyboardBinding::IsTapped()
|
||||
{
|
||||
return Keyboard::GetInstance()->IsTapped(Keycode);
|
||||
}
|
||||
|
||||
bool KeyboardBinding::IsReleased()
|
||||
{
|
||||
return Keyboard::GetInstance()->IsReleased(Keycode);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include "IInputBinding.h"
|
||||
#include "../Keyboard/Keyboard.h"
|
||||
|
||||
namespace TLAC::Input
|
||||
{
|
||||
class KeyboardBinding : public IInputBinding
|
||||
{
|
||||
public:
|
||||
BYTE Keycode;
|
||||
|
||||
KeyboardBinding(BYTE keycode);
|
||||
~KeyboardBinding();
|
||||
|
||||
bool IsDown() override;
|
||||
bool IsTapped() override;
|
||||
bool IsReleased() override;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
#include "MouseBinding.h"
|
||||
#include "../Keyboard/Keyboard.h"
|
||||
|
||||
namespace TLAC::Input
|
||||
{
|
||||
MouseBinding::MouseBinding(MouseAction action) : Action(action)
|
||||
{
|
||||
}
|
||||
|
||||
MouseBinding::~MouseBinding()
|
||||
{
|
||||
}
|
||||
|
||||
bool MouseBinding::IsDown()
|
||||
{
|
||||
switch (Action)
|
||||
{
|
||||
case MouseAction_LeftButton:
|
||||
return Keyboard::GetInstance()->IsDown(MK_LBUTTON);
|
||||
case MouseAction_RightButton:
|
||||
return Keyboard::GetInstance()->IsDown(MK_RBUTTON);
|
||||
case MouseAction_MiddleButton:
|
||||
return Keyboard::GetInstance()->IsDown(MK_MBUTTON);
|
||||
case MouseAction_ScrollUp:
|
||||
return Mouse::GetInstance()->GetIsScrolledUp();
|
||||
case MouseAction_ScrollDown:
|
||||
return Mouse::GetInstance()->GetIsScrolledDown();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool MouseBinding::IsTapped()
|
||||
{
|
||||
switch (Action)
|
||||
{
|
||||
case MouseAction_LeftButton:
|
||||
return Keyboard::GetInstance()->IsTapped(MK_LBUTTON);
|
||||
case MouseAction_RightButton:
|
||||
return Keyboard::GetInstance()->IsTapped(MK_RBUTTON);
|
||||
case MouseAction_MiddleButton:
|
||||
return Keyboard::GetInstance()->IsTapped(MK_MBUTTON);
|
||||
case MouseAction_ScrollUp:
|
||||
return Mouse::GetInstance()->GetIsScrolledUp();
|
||||
case MouseAction_ScrollDown:
|
||||
return Mouse::GetInstance()->GetIsScrolledDown();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool MouseBinding::IsReleased()
|
||||
{
|
||||
switch (Action)
|
||||
{
|
||||
case MouseAction_LeftButton:
|
||||
return Keyboard::GetInstance()->IsReleased(MK_LBUTTON);
|
||||
case MouseAction_RightButton:
|
||||
return Keyboard::GetInstance()->IsReleased(MK_RBUTTON);
|
||||
case MouseAction_MiddleButton:
|
||||
return Keyboard::GetInstance()->IsReleased(MK_MBUTTON);
|
||||
case MouseAction_ScrollUp:
|
||||
return Mouse::GetInstance()->GetWasScrolledUp();
|
||||
case MouseAction_ScrollDown:
|
||||
return Mouse::GetInstance()->GetWasScrolledDown();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include "IInputBinding.h"
|
||||
#include "../Mouse/Mouse.h"
|
||||
|
||||
namespace TLAC::Input
|
||||
{
|
||||
enum MouseAction
|
||||
{
|
||||
MouseAction_LeftButton,
|
||||
MouseAction_RightButton,
|
||||
MouseAction_MiddleButton,
|
||||
MouseAction_ScrollUp,
|
||||
MouseAction_ScrollDown,
|
||||
};
|
||||
|
||||
class MouseBinding : public IInputBinding
|
||||
{
|
||||
public:
|
||||
MouseAction Action;
|
||||
|
||||
MouseBinding(MouseAction action);
|
||||
~MouseBinding();
|
||||
|
||||
bool IsDown() override;
|
||||
bool IsTapped() override;
|
||||
bool IsReleased() override;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#include "XinputBinding.h"
|
||||
#include "..\Xinput\Xinput.h"
|
||||
|
||||
namespace TLAC::Input
|
||||
{
|
||||
XinputBinding::XinputBinding(BYTE keycode) : Keycode(keycode)
|
||||
{
|
||||
}
|
||||
|
||||
XinputBinding::~XinputBinding()
|
||||
{
|
||||
}
|
||||
|
||||
bool XinputBinding::IsDown()
|
||||
{
|
||||
return Xinput::GetInstance()->IsDown(Keycode);
|
||||
}
|
||||
|
||||
bool XinputBinding::IsTapped()
|
||||
{
|
||||
return Xinput::GetInstance()->IsTapped(Keycode);
|
||||
}
|
||||
|
||||
bool XinputBinding::IsReleased()
|
||||
{
|
||||
return Xinput::GetInstance()->IsReleased(Keycode);
|
||||
}
|
||||
|
||||
bool XinputBinding::IsDoubleTapped()
|
||||
{
|
||||
return Xinput::GetInstance()->IsDoubleTapped(Keycode);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include "IInputBinding.h"
|
||||
#include <windows.h>
|
||||
#include <vector>
|
||||
|
||||
namespace TLAC::Input
|
||||
{
|
||||
class XinputBinding : public IInputBinding
|
||||
{
|
||||
public:
|
||||
BYTE Keycode;
|
||||
|
||||
XinputBinding(BYTE keycode);
|
||||
~XinputBinding();
|
||||
|
||||
bool IsDown() override;
|
||||
bool IsTapped() override;
|
||||
bool IsReleased() override;
|
||||
bool IsDoubleTapped();
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#include "Controller.h"
|
||||
|
||||
namespace TLAC::Input
|
||||
{
|
||||
Controller::Controller()
|
||||
{
|
||||
}
|
||||
|
||||
Controller::~Controller()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include "DirectInputDevice.h"
|
||||
|
||||
namespace TLAC::Input
|
||||
{
|
||||
class Controller : public DirectInputDevice
|
||||
{
|
||||
protected:
|
||||
Controller();
|
||||
~Controller();
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#include "DirectInput.h"
|
||||
|
||||
namespace TLAC::Input
|
||||
{
|
||||
IDirectInput8 *IDirectInputInstance = nullptr;
|
||||
|
||||
HRESULT InitializeDirectInput(HMODULE module)
|
||||
{
|
||||
HRESULT result = DirectInput8Create(module, DIRECTINPUT_VERSION, IID_IDirectInput8, (VOID**)&IDirectInputInstance, nullptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool DirectInputInitialized()
|
||||
{
|
||||
return IDirectInputInstance != nullptr;
|
||||
}
|
||||
|
||||
void DisposeDirectInput()
|
||||
{
|
||||
if (IDirectInputInstance == nullptr)
|
||||
return;
|
||||
|
||||
IDirectInputInstance->Release();
|
||||
IDirectInputInstance = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#define DIRECTINPUT_VERSION 0x0800
|
||||
#include <dinput.h>
|
||||
|
||||
namespace TLAC::Input
|
||||
{
|
||||
extern IDirectInput8 *IDirectInputInstance;
|
||||
|
||||
HRESULT InitializeDirectInput(HMODULE module);
|
||||
bool DirectInputInitialized();
|
||||
void DisposeDirectInput();
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
#include "DirectInputDevice.h"
|
||||
|
||||
namespace TLAC::Input
|
||||
{
|
||||
HRESULT DirectInputDevice::DI_CreateDevice(const GUID &guid)
|
||||
{
|
||||
if (!DirectInputInitialized())
|
||||
return DIERR_NOTINITIALIZED;
|
||||
|
||||
HRESULT result = IDirectInputInstance->CreateDevice(guid, &directInputdevice, NULL);
|
||||
return result;
|
||||
}
|
||||
|
||||
HRESULT DirectInputDevice::DI_SetDataFormat(LPCDIDATAFORMAT dataFormat)
|
||||
{
|
||||
HRESULT result = directInputdevice->SetDataFormat(dataFormat);
|
||||
return result;
|
||||
}
|
||||
|
||||
HRESULT DirectInputDevice::DI_SetCooperativeLevel(HWND windowHandle, DWORD flags)
|
||||
{
|
||||
HRESULT result = directInputdevice->SetCooperativeLevel(windowHandle, flags);
|
||||
return result;
|
||||
}
|
||||
|
||||
HRESULT DirectInputDevice::DI_Acquire()
|
||||
{
|
||||
HRESULT result = directInputdevice->Acquire();
|
||||
return result;
|
||||
}
|
||||
|
||||
HRESULT DirectInputDevice::DI_Unacquire()
|
||||
{
|
||||
HRESULT result = directInputdevice->Unacquire();
|
||||
return result;
|
||||
}
|
||||
|
||||
HRESULT DirectInputDevice::DI_Release()
|
||||
{
|
||||
HRESULT result = directInputdevice->Release();
|
||||
return result;
|
||||
}
|
||||
|
||||
HRESULT DirectInputDevice::DI_Poll()
|
||||
{
|
||||
HRESULT result = directInputdevice->Poll();
|
||||
return result;
|
||||
}
|
||||
|
||||
HRESULT DirectInputDevice::DI_GetDeviceState(DWORD size, LPVOID data)
|
||||
{
|
||||
HRESULT result = directInputdevice->GetDeviceState(size, data);
|
||||
return result;
|
||||
}
|
||||
|
||||
void DirectInputDevice::DI_Dispose()
|
||||
{
|
||||
if (directInputdevice == nullptr)
|
||||
return;
|
||||
|
||||
HRESULT result = NULL;
|
||||
|
||||
result = DI_Unacquire();
|
||||
result = DI_Release();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
#include "DirectInput.h"
|
||||
|
||||
namespace TLAC::Input
|
||||
{
|
||||
class DirectInputDevice
|
||||
{
|
||||
protected:
|
||||
IDirectInputDevice8 *directInputdevice;
|
||||
|
||||
HRESULT DI_CreateDevice(const GUID& guid);
|
||||
HRESULT DI_SetDataFormat(LPCDIDATAFORMAT dataFormat);
|
||||
HRESULT DI_SetCooperativeLevel(HWND windowHandle, DWORD flags);
|
||||
HRESULT DI_Acquire();
|
||||
HRESULT DI_Unacquire();
|
||||
HRESULT DI_Release();
|
||||
HRESULT DI_Poll();
|
||||
HRESULT DI_GetDeviceState(DWORD size, LPVOID data);
|
||||
|
||||
void DI_Dispose();
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#include "DirectInputMouse.h"
|
||||
|
||||
namespace TLAC::Input
|
||||
{
|
||||
DirectInputMouse::DirectInputMouse()
|
||||
{
|
||||
HRESULT result = NULL;
|
||||
|
||||
result = DI_CreateDevice(GUID_SysMouse);
|
||||
|
||||
if (FAILED(result))
|
||||
return;
|
||||
|
||||
result = DI_SetDataFormat(&c_dfDIMouse);
|
||||
result = DI_Acquire();
|
||||
}
|
||||
|
||||
DirectInputMouse::~DirectInputMouse()
|
||||
{
|
||||
DI_Dispose();
|
||||
}
|
||||
|
||||
bool DirectInputMouse::Poll()
|
||||
{
|
||||
if (!DirectInputInitialized())
|
||||
return FALSE;
|
||||
|
||||
HRESULT result = NULL;
|
||||
|
||||
result = DI_Poll();
|
||||
result = DI_GetDeviceState(sizeof(mouseState), &mouseState);
|
||||
|
||||
return !FAILED(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include "DirectInputDevice.h"
|
||||
|
||||
namespace TLAC::Input
|
||||
{
|
||||
class DirectInputMouse : public DirectInputDevice
|
||||
{
|
||||
public:
|
||||
DirectInputMouse();
|
||||
~DirectInputMouse();
|
||||
|
||||
bool Poll();
|
||||
|
||||
inline long GetXPosition() { return mouseState.lX; };
|
||||
inline long GetYPosition() { return mouseState.lY; };
|
||||
inline long GetMouseWheel() { return mouseState.lZ; };
|
||||
|
||||
private:
|
||||
DIMOUSESTATE mouseState;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
namespace TLAC::Input
|
||||
{
|
||||
enum Direction
|
||||
{
|
||||
DIR_UP,
|
||||
DIR_RIGHT,
|
||||
DIR_DOWN,
|
||||
DIR_LEFT
|
||||
};
|
||||
|
||||
enum Ds4Button : int
|
||||
{
|
||||
DS4_SQUARE = 0,
|
||||
DS4_CROSS = 1,
|
||||
DS4_CIRCLE = 2,
|
||||
DS4_TRIANGLE = 3,
|
||||
|
||||
DS4_L1 = 4,
|
||||
DS4_R1 = 5,
|
||||
|
||||
DS4_L_TRIGGER = 6,
|
||||
DS4_R_TRIGGER = 7,
|
||||
|
||||
DS4_SHARE = 8,
|
||||
DS4_OPTIONS = 9,
|
||||
|
||||
DS4_L3 = 10,
|
||||
DS4_R3 = 11,
|
||||
|
||||
DS4_PS = 12,
|
||||
DS4_TOUCH = 13,
|
||||
|
||||
DS4_DPAD_UP,
|
||||
DS4_DPAD_RIGHT,
|
||||
DS4_DPAD_DOWN,
|
||||
DS4_DPAD_LEFT,
|
||||
|
||||
DS4_L_STICK_UP,
|
||||
DS4_L_STICK_RIGHT,
|
||||
DS4_L_STICK_DOWN,
|
||||
DS4_L_STICK_LEFT,
|
||||
|
||||
DS4_R_STICK_UP,
|
||||
DS4_R_STICK_RIGHT,
|
||||
DS4_R_STICK_DOWN,
|
||||
DS4_R_STICK_LEFT,
|
||||
|
||||
DS4_BUTTON_MAX,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#include "Ds4State.h"
|
||||
|
||||
namespace TLAC::Input
|
||||
{
|
||||
Joystick::Joystick() : XAxis(0.0f), YAxis(0.0f)
|
||||
{
|
||||
return;
|
||||
};
|
||||
|
||||
Joystick::Joystick(float xAxis, float yAxis) : XAxis(xAxis), YAxis(yAxis)
|
||||
{
|
||||
return;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
#include "../DirectInput.h"
|
||||
#include "Ds4Button.h"
|
||||
|
||||
namespace TLAC::Input
|
||||
{
|
||||
struct Joystick
|
||||
{
|
||||
FLOAT XAxis, YAxis;
|
||||
|
||||
Joystick();
|
||||
Joystick(float xAxis, float yAxis);
|
||||
};
|
||||
|
||||
struct Dpad
|
||||
{
|
||||
BOOL IsDown;
|
||||
FLOAT Angle;
|
||||
Joystick Stick;
|
||||
};
|
||||
|
||||
struct Trigger
|
||||
{
|
||||
FLOAT Axis;
|
||||
};
|
||||
|
||||
struct Ds4State
|
||||
{
|
||||
DIJOYSTATE2 DI_JoyState;
|
||||
|
||||
BYTE Buttons[DS4_BUTTON_MAX];
|
||||
|
||||
Dpad Dpad;
|
||||
Joystick LeftStick;
|
||||
Joystick RightStick;
|
||||
Trigger LeftTrigger;
|
||||
Trigger RightTrigger;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
#include "DualShock4.h"
|
||||
#include "../../../Utilities/Math.h"
|
||||
#include "../../../framework.h"
|
||||
#include <stdio.h>
|
||||
|
||||
namespace TLAC::Input
|
||||
{
|
||||
DualShock4* DualShock4::instance;
|
||||
|
||||
DualShock4::DualShock4()
|
||||
{
|
||||
}
|
||||
|
||||
DualShock4::~DualShock4()
|
||||
{
|
||||
DI_Dispose();
|
||||
}
|
||||
|
||||
bool DualShock4::TryInitializeInstance()
|
||||
{
|
||||
if (InstanceInitialized())
|
||||
return true;
|
||||
|
||||
if (!DirectInputInitialized())
|
||||
return false;
|
||||
|
||||
DualShock4 *dualShock4 = new DualShock4();
|
||||
|
||||
bool success = dualShock4->Initialize();
|
||||
instance = success ? dualShock4 : nullptr;
|
||||
|
||||
if (!success)
|
||||
delete dualShock4;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool DualShock4::Initialize()
|
||||
{
|
||||
HRESULT result = NULL;
|
||||
|
||||
const size_t guidCount = sizeof(GUID_Ds4) / sizeof(GUID);
|
||||
for (size_t i = 0; i < guidCount; i++)
|
||||
{
|
||||
result = DI_CreateDevice(GUID_Ds4[i]);
|
||||
|
||||
if (!FAILED(result))
|
||||
break;
|
||||
else if (i == guidCount - 1)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (FAILED(result = DI_SetDataFormat(&c_dfDIJoystick2)))
|
||||
return false;
|
||||
|
||||
result = DI_Acquire();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DualShock4::PollInput()
|
||||
{
|
||||
lastState = currentState;
|
||||
|
||||
HRESULT result = NULL;
|
||||
result = DI_Poll();
|
||||
result = DI_GetDeviceState(sizeof(DIJOYSTATE2), ¤tState.DI_JoyState);
|
||||
|
||||
if (result != DI_OK)
|
||||
return false;
|
||||
|
||||
UpdateInternalDs4State(currentState);
|
||||
|
||||
for (int button = 0; button < DS4_BUTTON_MAX; button++)
|
||||
currentState.Buttons[button] = GetButtonState(currentState, (Ds4Button)button);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DualShock4::UpdateInternalDs4State(Ds4State &state)
|
||||
{
|
||||
if (state.Dpad.IsDown = state.DI_JoyState.rgdwPOV[0] != -1)
|
||||
{
|
||||
state.Dpad.Angle = (state.DI_JoyState.rgdwPOV[0] / 100.0f);
|
||||
|
||||
auto direction = Utilities::GetDirection(state.Dpad.Angle);
|
||||
state.Dpad.Stick = { direction.Y, -direction.X };
|
||||
}
|
||||
else
|
||||
{
|
||||
state.Dpad.Angle = 0;
|
||||
state.Dpad.Stick = Joystick();
|
||||
}
|
||||
|
||||
state.LeftStick = NormalizeStick(state.DI_JoyState.lX, state.DI_JoyState.lY);
|
||||
state.RightStick = NormalizeStick(state.DI_JoyState.lZ, state.DI_JoyState.lRz);
|
||||
|
||||
state.LeftTrigger = { NormalizeTrigger(state.DI_JoyState.lRx) };
|
||||
state.RightTrigger = { NormalizeTrigger(state.DI_JoyState.lRy) };
|
||||
}
|
||||
|
||||
bool DualShock4::IsDown(Ds4Button button)
|
||||
{
|
||||
return currentState.Buttons[button];
|
||||
}
|
||||
|
||||
bool DualShock4::IsUp(Ds4Button button)
|
||||
{
|
||||
return !IsDown(button);
|
||||
}
|
||||
|
||||
bool DualShock4::IsTapped(Ds4Button button)
|
||||
{
|
||||
return IsDown(button) && WasUp(button);
|
||||
}
|
||||
|
||||
bool DualShock4::IsReleased(Ds4Button button)
|
||||
{
|
||||
return IsUp(button) && WasDown(button);
|
||||
}
|
||||
|
||||
bool DualShock4::WasDown(Ds4Button button)
|
||||
{
|
||||
return lastState.Buttons[button];
|
||||
}
|
||||
|
||||
bool DualShock4::WasUp(Ds4Button button)
|
||||
{
|
||||
return !WasDown(button);
|
||||
}
|
||||
|
||||
bool DualShock4::MatchesDirection(Joystick joystick, Direction directionEnum, float threshold)
|
||||
{
|
||||
switch (directionEnum)
|
||||
{
|
||||
case TLAC::Input::DIR_UP:
|
||||
return joystick.YAxis <= -threshold;
|
||||
|
||||
case TLAC::Input::DIR_RIGHT:
|
||||
return joystick.XAxis >= +threshold;
|
||||
|
||||
case TLAC::Input::DIR_DOWN:
|
||||
return joystick.YAxis >= +threshold;
|
||||
|
||||
case TLAC::Input::DIR_LEFT:
|
||||
return joystick.XAxis <= -threshold;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool DualShock4::GetButtonState(Ds4State &state, Ds4Button button)
|
||||
{
|
||||
if (button >= DS4_SQUARE && button <= DS4_TOUCH)
|
||||
return state.DI_JoyState.rgbButtons[button];
|
||||
|
||||
if (button >= DS4_DPAD_UP && button <= DS4_DPAD_LEFT)
|
||||
return state.Dpad.IsDown ? MatchesDirection(state.Dpad.Stick, (Direction)(button - DS4_DPAD_UP), dpadThreshold) : false;
|
||||
|
||||
if (button >= DS4_L_STICK_UP && button <= DS4_L_STICK_LEFT)
|
||||
return MatchesDirection(state.LeftStick, (Direction)(button - DS4_L_STICK_UP), joystickThreshold);
|
||||
|
||||
if (button >= DS4_R_STICK_UP && button <= DS4_R_STICK_LEFT)
|
||||
return MatchesDirection(state.RightStick, (Direction)(button - DS4_R_STICK_UP), joystickThreshold);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
#include "../Controller.h"
|
||||
#include "../../IInputDevice.h"
|
||||
#include "Ds4State.h"
|
||||
|
||||
namespace TLAC::Input
|
||||
{
|
||||
// DualShock 4 Wireless Controller Product GUIDs:
|
||||
const GUID GUID_Ds4[2] =
|
||||
{
|
||||
// First Generation: {05C4054C-0000-0000-0000-504944564944}
|
||||
{ 0x05C4054C, 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } },
|
||||
// Second Generation: {09CC054C-0000-0000-0000-504944564944}
|
||||
{ 0x09CC054C, 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } },
|
||||
};
|
||||
|
||||
class DualShock4 : public Controller, public IInputDevice
|
||||
{
|
||||
public:
|
||||
DualShock4();
|
||||
~DualShock4();
|
||||
|
||||
static bool TryInitializeInstance();
|
||||
|
||||
bool Initialize();
|
||||
bool PollInput() override;
|
||||
|
||||
bool IsDown(Ds4Button button);
|
||||
bool IsUp(Ds4Button button);
|
||||
bool IsTapped(Ds4Button button);
|
||||
bool IsReleased(Ds4Button button);
|
||||
bool WasDown(Ds4Button button);
|
||||
bool WasUp(Ds4Button button);
|
||||
|
||||
inline Joystick GetLeftStick() { return currentState.LeftStick; };
|
||||
inline Joystick GetRightStick() { return currentState.RightStick; };
|
||||
inline Joystick GetDpad() { return currentState.Dpad.Stick; };
|
||||
|
||||
static inline bool InstanceInitialized() { return instance != nullptr; };
|
||||
static inline DualShock4* GetInstance() { return instance; };
|
||||
static inline void DeleteInstance() { delete instance; instance = nullptr; };
|
||||
|
||||
private:
|
||||
static DualShock4* instance;
|
||||
|
||||
Ds4State lastState;
|
||||
Ds4State currentState;
|
||||
|
||||
const float triggerThreshold = 0.5f;
|
||||
const float joystickThreshold = 0.5f;
|
||||
const float dpadThreshold = 0.5f;
|
||||
|
||||
inline float NormalizeTrigger(long value) { return (float)value / USHRT_MAX; };
|
||||
inline float NormalizeStick(long value) { return (float)value / USHRT_MAX * 2.0f - 1.0f; };
|
||||
inline Joystick NormalizeStick(long x, long y) { return Joystick(NormalizeStick(x), NormalizeStick(y)); };
|
||||
|
||||
void UpdateInternalDs4State(Ds4State &state);
|
||||
|
||||
bool MatchesDirection(Joystick joystick, Direction directionEnum, float threshold);
|
||||
bool GetButtonState(Ds4State &state, Ds4Button button);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
namespace TLAC::Input
|
||||
{
|
||||
class IInputDevice
|
||||
{
|
||||
public:
|
||||
virtual bool PollInput() = 0;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,275 @@
|
||||
#include "Config.h"
|
||||
#include "windows.h"
|
||||
#include "../Bindings/KeyboardBinding.h"
|
||||
#include "../Bindings/Ds4Binding.h"
|
||||
#include "../../Utilities/Operations.h"
|
||||
#include "../Bindings/XinputBinding.h"
|
||||
#include "../../Constants.h"
|
||||
|
||||
namespace TLAC::Input::KeyConfig
|
||||
{
|
||||
KeycodeMap Config::Keymap =
|
||||
{
|
||||
// NumPad Keys
|
||||
{ "NumPad0", VK_NUMPAD0 },
|
||||
{ "NumPad1", VK_NUMPAD1 },
|
||||
{ "NumPad2", VK_NUMPAD2 },
|
||||
{ "NumPad3", VK_NUMPAD3 },
|
||||
{ "NumPad4", VK_NUMPAD4 },
|
||||
{ "NumPad5", VK_NUMPAD5 },
|
||||
{ "NumPad6", VK_NUMPAD6 },
|
||||
{ "NumPad7", VK_NUMPAD7 },
|
||||
{ "NumPad8", VK_NUMPAD8 },
|
||||
{ "NumPad9", VK_NUMPAD9 },
|
||||
{ "Plus", VK_ADD },
|
||||
{ "Minus", VK_SUBTRACT },
|
||||
{ "Divide", VK_DIVIDE },
|
||||
{ "Multiply", VK_MULTIPLY },
|
||||
{ "Comma", VK_OEM_COMMA },
|
||||
{ "Period", VK_OEM_PERIOD },
|
||||
{ "Slash", VK_OEM_2 },
|
||||
// F-Keys
|
||||
{ "F1", VK_F1 },
|
||||
{ "F2", VK_F2 },
|
||||
{ "F3", VK_F3 },
|
||||
{ "F4", VK_F4 },
|
||||
{ "F5", VK_F5 },
|
||||
{ "F6", VK_F6 },
|
||||
{ "F7", VK_F7 },
|
||||
{ "F8", VK_F8 },
|
||||
{ "F9", VK_F9 },
|
||||
{ "F10", VK_F10 },
|
||||
{ "F11", VK_F11 },
|
||||
{ "F12", VK_F12 },
|
||||
{ "F13", VK_F13 },
|
||||
{ "F14", VK_F14 },
|
||||
{ "F15", VK_F15 },
|
||||
{ "F16", VK_F16 },
|
||||
{ "F17", VK_F17 },
|
||||
{ "F18", VK_F18 },
|
||||
{ "F19", VK_F19 },
|
||||
{ "F20", VK_F20 },
|
||||
{ "F21", VK_F21 },
|
||||
{ "F22", VK_F22 },
|
||||
{ "F23", VK_F23 },
|
||||
{ "F24", VK_F24 },
|
||||
// Shift Keys
|
||||
{ "LeftShift", VK_LSHIFT },
|
||||
{ "LShift", VK_LSHIFT },
|
||||
{ "RightShift", VK_RSHIFT },
|
||||
{ "RShift", VK_RSHIFT },
|
||||
// Control Keys
|
||||
{ "LeftControl", VK_LCONTROL },
|
||||
{ "LControl", VK_LCONTROL },
|
||||
{ "LCtrl", VK_LCONTROL },
|
||||
{ "RightControl", VK_RCONTROL },
|
||||
{ "RControl", VK_RCONTROL },
|
||||
{ "RCtrl", VK_RCONTROL },
|
||||
// Arrow Keys
|
||||
{ "Up", VK_UP },
|
||||
{ "Down", VK_DOWN },
|
||||
{ "Left", VK_LEFT },
|
||||
{ "Right", VK_RIGHT },
|
||||
// Special Keys
|
||||
{ "Enter", VK_RETURN },
|
||||
{ "Return", VK_RETURN },
|
||||
{ "Tab", VK_TAB },
|
||||
{ "Back", VK_BACK },
|
||||
{ "Backspace", VK_BACK },
|
||||
{ "Insert", VK_INSERT },
|
||||
{ "Ins", VK_INSERT },
|
||||
{ "Delete", VK_DELETE },
|
||||
{ "Del", VK_DELETE },
|
||||
{ "Home", VK_HOME },
|
||||
{ "End", VK_END },
|
||||
{ "PageUp", VK_PRIOR },
|
||||
{ "PageDown", VK_NEXT },
|
||||
{ "ESC", VK_ESCAPE },
|
||||
{ "Escape", VK_ESCAPE },
|
||||
{ "Comma", VK_OEM_COMMA },
|
||||
{ "Period", VK_OEM_PERIOD },
|
||||
{ "Slash", VK_OEM_2 },
|
||||
// Mouse buttons
|
||||
{ "MouseLeft", VK_LBUTTON },
|
||||
{ "MouseMiddle", VK_MBUTTON },
|
||||
{ "MouseRight", VK_RBUTTON },
|
||||
{ "MouseX1", VK_XBUTTON1 },
|
||||
{ "MouseX2", VK_XBUTTON2 },
|
||||
};
|
||||
|
||||
KeycodeMap Config::XinputMap =
|
||||
{
|
||||
//XINPUT
|
||||
{ "XINPUT_A", XINPUT_A},
|
||||
{ "XINPUT_B", XINPUT_B},
|
||||
{ "XINPUT_X", XINPUT_X},
|
||||
{ "XINPUT_Y", XINPUT_Y},
|
||||
{ "XINPUT_UP", XINPUT_UP},
|
||||
{ "XINPUT_DOWN", XINPUT_DOWN},
|
||||
{ "XINPUT_LEFT", XINPUT_LEFT},
|
||||
{ "XINPUT_RIGHT", XINPUT_RIGHT},
|
||||
{ "XINPUT_START", XINPUT_START},
|
||||
{ "XINPUT_BACK", XINPUT_BACK},
|
||||
{ "XINPUT_LS", XINPUT_LS},
|
||||
{ "XINPUT_RS", XINPUT_RS},
|
||||
{ "XINPUT_LB", XINPUT_LS},
|
||||
{ "XINPUT_RB", XINPUT_RS},
|
||||
{ "XINPUT_LT", XINPUT_LT},
|
||||
{ "XINPUT_RT", XINPUT_RT},
|
||||
{ "XINPUT_LSB", XINPUT_LSB},
|
||||
{ "XINPUT_RSB", XINPUT_RSB},
|
||||
{ "XINPUT_LLEFT", XINPUT_LLEFT},
|
||||
{ "XINPUT_LRIGHT", XINPUT_LRIGHT},
|
||||
{ "XINPUT_RLEFT", XINPUT_RLEFT},
|
||||
{ "XINPUT_RRIGHT", XINPUT_RRIGHT},
|
||||
};
|
||||
|
||||
Ds4ButtonMap Config::Ds4Map =
|
||||
{
|
||||
// Face Buttons
|
||||
{ "DS4_SQUARE", DS4_SQUARE },
|
||||
{ "Ds4_Square", DS4_SQUARE },
|
||||
|
||||
{ "DS4_CROSS", DS4_CROSS },
|
||||
{ "Ds4_Cross", DS4_CROSS },
|
||||
|
||||
{ "DS4_CIRCLE", DS4_CIRCLE },
|
||||
{ "Ds4_Circle", DS4_CIRCLE },
|
||||
|
||||
{ "DS4_TRIANGLE", DS4_TRIANGLE },
|
||||
{ "Ds4_Triangle", DS4_TRIANGLE },
|
||||
|
||||
// Standard Buttons
|
||||
{ "DS4_SHARE", DS4_SHARE },
|
||||
{ "Ds4_Share", DS4_SHARE },
|
||||
|
||||
{ "DS4_OPTIONS", DS4_OPTIONS },
|
||||
{ "Ds4_Options", DS4_OPTIONS },
|
||||
|
||||
{ "DS4_PS", DS4_PS },
|
||||
{ "Ds4_PS", DS4_PS },
|
||||
|
||||
{ "DS4_TOUCH", DS4_TOUCH },
|
||||
{ "Ds4_Touch", DS4_TOUCH },
|
||||
|
||||
{ "DS4_L1", DS4_L1 },
|
||||
{ "Ds4_L1", DS4_L1 },
|
||||
|
||||
{ "DS4_R1", DS4_R1 },
|
||||
{ "Ds4_R1", DS4_R1 },
|
||||
|
||||
// D-Pad Directions
|
||||
{ "DS4_DPAD_UP", DS4_DPAD_UP },
|
||||
{ "Ds4_DPad_Up", DS4_DPAD_UP },
|
||||
|
||||
{ "DS4_DPAD_RIGHT", DS4_DPAD_RIGHT },
|
||||
{ "Ds4_DPad_Right", DS4_DPAD_RIGHT },
|
||||
|
||||
{ "DS4_DPAD_DOWN", DS4_DPAD_DOWN },
|
||||
{ "Ds4_DPad_Down", DS4_DPAD_DOWN },
|
||||
|
||||
{ "DS4_DPAD_LEFT", DS4_DPAD_LEFT },
|
||||
{ "Ds4_DPad_Left", DS4_DPAD_LEFT },
|
||||
|
||||
// Trigger Buttons
|
||||
{ "DS4_L_TRIGGER", DS4_L_TRIGGER },
|
||||
{ "Ds4_L_Trigger", DS4_L_TRIGGER },
|
||||
|
||||
{ "DS4_R_TRIGGER", DS4_R_TRIGGER },
|
||||
{ "Ds4_R_Trigger", DS4_R_TRIGGER },
|
||||
|
||||
// Joystick Buttons
|
||||
{ "DS4_L3", DS4_L3 },
|
||||
{ "Ds4_L3", DS4_L3 },
|
||||
|
||||
{ "DS4_R3", DS4_R3 },
|
||||
{ "Ds4_R3", DS4_R3 },
|
||||
|
||||
// Left Joystick
|
||||
{ "DS4_L_STICK_UP", DS4_L_STICK_UP },
|
||||
{ "Ds4_L_Stick_Up", DS4_L_STICK_UP },
|
||||
|
||||
{ "DS4_L_STICK_RIGHT", DS4_L_STICK_RIGHT },
|
||||
{ "Ds4_L_Stick_Right", DS4_L_STICK_RIGHT },
|
||||
|
||||
{ "DS4_L_STICK_DOWN", DS4_L_STICK_DOWN },
|
||||
{ "Ds4_L_Stick_Down", DS4_L_STICK_DOWN },
|
||||
|
||||
{ "DS4_L_STICK_LEFT", DS4_L_STICK_LEFT },
|
||||
{ "Ds4_L_Stick_Left", DS4_L_STICK_LEFT },
|
||||
|
||||
// Right Joystick
|
||||
{ "DS4_R_STICK_UP", DS4_R_STICK_UP },
|
||||
{ "Ds4_R_Stick_Up", DS4_R_STICK_UP },
|
||||
|
||||
{ "DS4_R_STICK_RIGHT", DS4_R_STICK_RIGHT },
|
||||
{ "Ds4_R_Stick_Right", DS4_R_STICK_RIGHT },
|
||||
|
||||
{ "DS4_R_STICK_DOWN", DS4_R_STICK_DOWN },
|
||||
{ "Ds4_R_Stick_Down", DS4_R_STICK_DOWN },
|
||||
|
||||
{ "DS4_R_STICK_LEFT", DS4_R_STICK_LEFT },
|
||||
{ "Ds4_R_Stick_Left", DS4_R_STICK_LEFT },
|
||||
};
|
||||
|
||||
void Config::BindConfigKeys(std::unordered_map<std::string, std::string> &configMap, const char *configKeyName, Binding &bindObj, std::vector<std::string> defaultKeys)
|
||||
{
|
||||
std::vector<std::string> keys;
|
||||
|
||||
auto configPair = configMap.find(configKeyName);
|
||||
|
||||
// config variable was found in the ini
|
||||
if (configPair != configMap.end())
|
||||
{
|
||||
keys = Utilities::Split(configPair->second, ",");
|
||||
}
|
||||
else
|
||||
{
|
||||
keys = defaultKeys;
|
||||
}
|
||||
|
||||
for (std::string key : keys)
|
||||
{
|
||||
Utilities::Trim(key);
|
||||
|
||||
// Applies only for Single-Character keys
|
||||
if (key.length() == 1)
|
||||
{
|
||||
bindObj.AddBinding(new KeyboardBinding(key[0]));
|
||||
}
|
||||
else // for special key names
|
||||
{
|
||||
auto keycode = Config::Keymap.find(key.c_str());
|
||||
|
||||
// name is known in the special keys map
|
||||
if (keycode != Config::Keymap.end())
|
||||
{
|
||||
bindObj.AddBinding(new KeyboardBinding(keycode->second));
|
||||
}
|
||||
else
|
||||
{
|
||||
auto xinputBtn = Config::XinputMap.find(key.c_str());
|
||||
|
||||
if (xinputBtn != Config::XinputMap.end())
|
||||
{
|
||||
bindObj.AddBinding(new XinputBinding(xinputBtn->second));
|
||||
}
|
||||
else
|
||||
{
|
||||
// just gonna be lazy for now and put this inside an else statement
|
||||
auto ds4Button = Config::Ds4Map.find(key.c_str());
|
||||
|
||||
if (ds4Button != Config::Ds4Map.end())
|
||||
{
|
||||
bindObj.AddBinding(new Ds4Binding(ds4Button->second));
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("[TLAC] Config::BindConfigKeys(): Unable to parse key: '%s'\n", key.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
#include "KeyString.h"
|
||||
#include "KeyStringHash.h"
|
||||
#include "../Bindings/Binding.h"
|
||||
#include "../DirectInput/Ds4/Ds4Button.h"
|
||||
|
||||
namespace TLAC::Input::KeyConfig
|
||||
{
|
||||
typedef std::unordered_map<KeyString, uint8_t, KeyStringHash> KeycodeMap;
|
||||
typedef std::unordered_map<KeyString, Ds4Button, KeyStringHash> Ds4ButtonMap;
|
||||
|
||||
class Config
|
||||
{
|
||||
public:
|
||||
static KeycodeMap Keymap;
|
||||
static Ds4ButtonMap Ds4Map;
|
||||
static KeycodeMap XinputMap;
|
||||
|
||||
static void BindConfigKeys(std::unordered_map<std::string, std::string> &configMap, const char *configKeyName, Binding &bindObj, std::vector<std::string> defaultKeys);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#include "KeyString.h"
|
||||
|
||||
namespace TLAC::Input::KeyConfig
|
||||
{
|
||||
KeyString::KeyString(const char* str) : value(str)
|
||||
{
|
||||
}
|
||||
|
||||
bool KeyString::operator==(const KeyString& rsv) const
|
||||
{
|
||||
return !_strcmpi(value.c_str(), rsv.value.c_str());
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user